home *** CD-ROM | disk | FTP | other *** search
/ Aminet 52 / Aminet 52 (2002)(GTI - Schatztruhe)[!][Dec 2002].iso / Aminet / dev / gg / ncurses-5.3.lha / ncurses-5.3 / test / ncurses.c < prev    next >
C/C++ Source or Header  |  2002-10-24  |  99KB  |  4,334 lines

  1. /****************************************************************************
  2.  * Copyright (c) 1998-2001,2002 Free Software Foundation, Inc.              *
  3.  *                                                                          *
  4.  * Permission is hereby granted, free of charge, to any person obtaining a  *
  5.  * copy of this software and associated documentation files (the            *
  6.  * "Software"), to deal in the Software without restriction, including      *
  7.  * without limitation the rights to use, copy, modify, merge, publish,      *
  8.  * distribute, distribute with modifications, sublicense, and/or sell       *
  9.  * copies of the Software, and to permit persons to whom the Software is    *
  10.  * furnished to do so, subject to the following conditions:                 *
  11.  *                                                                          *
  12.  * The above copyright notice and this permission notice shall be included  *
  13.  * in all copies or substantial portions of the Software.                   *
  14.  *                                                                          *
  15.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
  16.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
  17.  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
  18.  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
  19.  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
  20.  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
  21.  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
  22.  *                                                                          *
  23.  * Except as contained in this notice, the name(s) of the above copyright   *
  24.  * holders shall not be used in advertising or otherwise to promote the     *
  25.  * sale, use or other dealings in this Software without prior written       *
  26.  * authorization.                                                           *
  27.  ****************************************************************************/
  28. /****************************************************************************
  29.  
  30. NAME
  31.    ncurses.c --- ncurses library exerciser
  32.  
  33. SYNOPSIS
  34.    ncurses
  35.  
  36. DESCRIPTION
  37.    An interactive test module for the ncurses library.
  38.  
  39. AUTHOR
  40.    Author: Eric S. Raymond <esr@snark.thyrsus.com> 1993
  41.            Thomas E. Dickey (beginning revision 1.27 in 1996).
  42.  
  43. $Id: ncurses.c,v 1.180 2002/09/15 00:39:33 tom Exp $
  44.  
  45. ***************************************************************************/
  46.  
  47. #include <stdio.h>
  48. #include <ctype.h>
  49. #include <assert.h>
  50.  
  51. #include <test.priv.h>
  52.  
  53. #if HAVE_GETTIMEOFDAY
  54. #if HAVE_SYS_TIME_H && HAVE_SYS_TIME_SELECT
  55. #include <sys/time.h>
  56. #endif
  57. #if HAVE_SYS_SELECT_H
  58. #include <sys/select.h>
  59. #endif
  60. #endif
  61.  
  62. #if HAVE_PANEL_H && HAVE_LIBPANEL
  63. #define USE_LIBPANEL 1
  64. #include <panel.h>
  65. #else
  66. #define USE_LIBPANEL 0
  67. #endif
  68.  
  69. #if HAVE_MENU_H && HAVE_LIBMENU
  70. #define USE_LIBMENU 1
  71. #include <menu.h>
  72. #else
  73. #define USE_LIBMENU 0
  74. #endif
  75.  
  76. #if HAVE_FORM_H && HAVE_LIBFORM
  77. #define USE_LIBFORM 1
  78. #include <form.h>
  79. #else
  80. #define USE_LIBFORM 0
  81. #endif
  82.  
  83. #ifdef NCURSES_VERSION
  84.  
  85. #ifdef TRACE
  86. static int save_trace = TRACE_ORDINARY | TRACE_CALLS;
  87. extern int _nc_tracing;
  88. #endif
  89.  
  90. #else
  91.  
  92. #define mmask_t chtype        /* not specified in XSI */
  93.  
  94. #ifdef CURSES_ACS_ARRAY
  95. #define ACS_S3          (CURSES_ACS_ARRAY['p'])        /* scan line 3 */
  96. #define ACS_S7          (CURSES_ACS_ARRAY['r'])        /* scan line 7 */
  97. #define ACS_LEQUAL      (CURSES_ACS_ARRAY['y'])        /* less/equal */
  98. #define ACS_GEQUAL      (CURSES_ACS_ARRAY['z'])        /* greater/equal */
  99. #define ACS_PI          (CURSES_ACS_ARRAY['{'])        /* Pi */
  100. #define ACS_NEQUAL      (CURSES_ACS_ARRAY['|'])        /* not equal */
  101. #define ACS_STERLING    (CURSES_ACS_ARRAY['}'])        /* UK pound sign */
  102. #else
  103. #define ACS_S3          (A_ALTCHARSET + 'p')    /* scan line 3 */
  104. #define ACS_S7          (A_ALTCHARSET + 'r')    /* scan line 7 */
  105. #define ACS_LEQUAL      (A_ALTCHARSET + 'y')    /* less/equal */
  106. #define ACS_GEQUAL      (A_ALTCHARSET + 'z')    /* greater/equal */
  107. #define ACS_PI          (A_ALTCHARSET + '{')    /* Pi */
  108. #define ACS_NEQUAL      (A_ALTCHARSET + '|')    /* not equal */
  109. #define ACS_STERLING    (A_ALTCHARSET + '}')    /* UK pound sign */
  110. #endif
  111.  
  112. #ifdef CURSES_WACS_ARRAY
  113. #define WACS_S3         (&(CURSES_WACS_ARRAY['p']))    /* scan line 3 */
  114. #define WACS_S7         (&(CURSES_WACS_ARRAY['r']))    /* scan line 7 */
  115. #define WACS_LEQUAL     (&(CURSES_WACS_ARRAY['y']))    /* less/equal */
  116. #define WACS_GEQUAL     (&(CURSES_WACS_ARRAY['z']))    /* greater/equal */
  117. #define WACS_PI         (&(CURSES_WACS_ARRAY['{']))    /* Pi */
  118. #define WACS_NEQUAL     (&(CURSES_WACS_ARRAY['|']))    /* not equal */
  119. #define WACS_STERLING   (&(CURSES_WACS_ARRAY['}']))    /* UK pound sign */
  120. #endif
  121.  
  122. #endif
  123.  
  124. #define P(string)    printw("%s\n", string)
  125. #ifdef CTRL
  126. #undef CTRL
  127. #endif
  128. #define CTRL(x)        ((x) & 0x1f)
  129.  
  130. #define QUIT        CTRL('Q')
  131. #define ESCAPE        CTRL('[')
  132. #define BLANK        ' '    /* this is the background character */
  133.  
  134. #undef max_colors
  135. static int max_colors;        /* the actual number of colors we'll use */
  136.  
  137. #undef max_pairs
  138. static int max_pairs;        /* ...and the number of color pairs */
  139.  
  140. /* The behavior of mvhline, mvvline for negative/zero length is unspecified,
  141.  * though we can rely on negative x/y values to stop the macro.
  142.  */
  143. static void
  144. do_h_line(int y, int x, chtype c, int to)
  145. {
  146.     if ((to) > (x))
  147.     mvhline(y, x, c, (to) - (x));
  148. }
  149.  
  150. static void
  151. do_v_line(int y, int x, chtype c, int to)
  152. {
  153.     if ((to) > (y))
  154.     mvvline(y, x, c, (to) - (y));
  155. }
  156.  
  157. /* Common function to allow ^T to toggle trace-mode in the middle of a test
  158.  * so that trace-files can be made smaller.
  159.  */
  160. static int
  161. wGetchar(WINDOW *win)
  162. {
  163.     int c;
  164. #ifdef TRACE
  165.     while ((c = wgetch(win)) == CTRL('T')) {
  166.     if (_nc_tracing) {
  167.         save_trace = _nc_tracing;
  168.         _tracef("TOGGLE-TRACING OFF");
  169.         _nc_tracing = 0;
  170.     } else {
  171.         _nc_tracing = save_trace;
  172.     }
  173.     trace(_nc_tracing);
  174.     if (_nc_tracing)
  175.         _tracef("TOGGLE-TRACING ON");
  176.     }
  177. #else
  178.     c = wgetch(win);
  179. #endif
  180.     return c;
  181. }
  182. #define Getchar() wGetchar(stdscr)
  183.  
  184. #if USE_WIDEC_SUPPORT
  185. static int
  186. wGet_wchar(WINDOW *win, wint_t * result)
  187. {
  188.     int c;
  189. #ifdef TRACE
  190.     while ((c = wget_wch(win, result)) == CTRL('T')) {
  191.     if (_nc_tracing) {
  192.         save_trace = _nc_tracing;
  193.         _tracef("TOGGLE-TRACING OFF");
  194.         _nc_tracing = 0;
  195.     } else {
  196.         _nc_tracing = save_trace;
  197.     }
  198.     trace(_nc_tracing);
  199.     if (_nc_tracing)
  200.         _tracef("TOGGLE-TRACING ON");
  201.     }
  202. #else
  203.     c = wget_wch(win, result);
  204. #endif
  205.     return c;
  206. }
  207. #define Get_wchar(result) wGet_wchar(stdscr, result)
  208.  
  209. #endif
  210.  
  211. static void
  212. Pause(void)
  213. {
  214.     move(LINES - 1, 0);
  215.     addstr("Press any key to continue... ");
  216.     (void) Getchar();
  217. }
  218.  
  219. static void
  220. Cannot(const char *what)
  221. {
  222.     printw("\nThis %s terminal %s\n\n", getenv("TERM"), what);
  223.     Pause();
  224. }
  225.  
  226. static void
  227. ShellOut(bool message)
  228. {
  229.     if (message)
  230.     addstr("Shelling out...");
  231.     def_prog_mode();
  232.     endwin();
  233.     system("sh");
  234.     if (message)
  235.     addstr("returned from shellout.\n");
  236.     refresh();
  237. }
  238.  
  239. #ifdef NCURSES_MOUSE_VERSION
  240. static const char *
  241. mouse_decode(MEVENT const *ep)
  242. {
  243.     static char buf[80];
  244.  
  245.     (void) sprintf(buf, "id %2d  at (%2d, %2d, %2d) state %4lx = {",
  246.            ep->id, ep->x, ep->y, ep->z, ep->bstate);
  247.  
  248. #define SHOW(m, s) if ((ep->bstate & m)==m) {strcat(buf,s); strcat(buf, ", ");}
  249.     SHOW(BUTTON1_RELEASED, "release-1");
  250.     SHOW(BUTTON1_PRESSED, "press-1");
  251.     SHOW(BUTTON1_CLICKED, "click-1");
  252.     SHOW(BUTTON1_DOUBLE_CLICKED, "doubleclick-1");
  253.     SHOW(BUTTON1_TRIPLE_CLICKED, "tripleclick-1");
  254.     SHOW(BUTTON1_RESERVED_EVENT, "reserved-1");
  255.     SHOW(BUTTON2_RELEASED, "release-2");
  256.     SHOW(BUTTON2_PRESSED, "press-2");
  257.     SHOW(BUTTON2_CLICKED, "click-2");
  258.     SHOW(BUTTON2_DOUBLE_CLICKED, "doubleclick-2");
  259.     SHOW(BUTTON2_TRIPLE_CLICKED, "tripleclick-2");
  260.     SHOW(BUTTON2_RESERVED_EVENT, "reserved-2");
  261.     SHOW(BUTTON3_RELEASED, "release-3");
  262.     SHOW(BUTTON3_PRESSED, "press-3");
  263.     SHOW(BUTTON3_CLICKED, "click-3");
  264.     SHOW(BUTTON3_DOUBLE_CLICKED, "doubleclick-3");
  265.     SHOW(BUTTON3_TRIPLE_CLICKED, "tripleclick-3");
  266.     SHOW(BUTTON3_RESERVED_EVENT, "reserved-3");
  267.     SHOW(BUTTON4_RELEASED, "release-4");
  268.     SHOW(BUTTON4_PRESSED, "press-4");
  269.     SHOW(BUTTON4_CLICKED, "click-4");
  270.     SHOW(BUTTON4_DOUBLE_CLICKED, "doubleclick-4");
  271.     SHOW(BUTTON4_TRIPLE_CLICKED, "tripleclick-4");
  272.     SHOW(BUTTON4_RESERVED_EVENT, "reserved-4");
  273.     SHOW(BUTTON_CTRL, "ctrl");
  274.     SHOW(BUTTON_SHIFT, "shift");
  275.     SHOW(BUTTON_ALT, "alt");
  276.     SHOW(ALL_MOUSE_EVENTS, "all-events");
  277.     SHOW(REPORT_MOUSE_POSITION, "position");
  278. #undef SHOW
  279.  
  280.     if (buf[strlen(buf) - 1] == ' ')
  281.     buf[strlen(buf) - 2] = '\0';
  282.     (void) strcat(buf, "}");
  283.     return (buf);
  284. }
  285. #endif /* NCURSES_MOUSE_VERSION */
  286.  
  287. /****************************************************************************
  288.  *
  289.  * Character input test
  290.  *
  291.  ****************************************************************************/
  292.  
  293. static void
  294. setup_getch(WINDOW *win, bool flags[])
  295. {
  296.     keypad(win, flags['k']);    /* should be redundant, but for testing */
  297.     meta(win, flags['m']);    /* force this to a known state */
  298.     if (flags['e'])
  299.     echo();
  300.     else
  301.     noecho();
  302. }
  303.  
  304. static void
  305. wgetch_help(WINDOW *win, bool flags[])
  306. {
  307.     static const char *help[] =
  308.     {
  309.     "e -- toggle echo mode"
  310.     ,"g -- triggers a getstr test"
  311.     ,"k -- toggle keypad/literal mode"
  312.     ,"m -- toggle meta (7-bit/8-bit) mode"
  313.     ,"q -- quit (x also exits)"
  314.     ,"s -- shell out\n"
  315.     ,"w -- create a new window"
  316. #ifdef SIGTSTP
  317.     ,"z -- suspend this process"
  318. #endif
  319.     };
  320.     int y, x;
  321.     unsigned chk = ((SIZEOF(help) + 1) / 2);
  322.     unsigned n;
  323.  
  324.     getyx(win, y, x);
  325.     move(0, 0);
  326.     printw("Type any key to see its %s value.  Also:\n",
  327.        flags['k'] ? "keypad" : "literal");
  328.     for (n = 0; n < SIZEOF(help); ++n) {
  329.     int row = 1 + (n % chk);
  330.     int col = (n >= chk) ? COLS / 2 : 0;
  331.     int flg = ((strstr(help[n], "toggle") != 0)
  332.            && (flags[UChar(*help[n])] != FALSE));
  333.     if (flg)
  334.         standout();
  335.     mvprintw(row, col, "%s", help[n]);
  336.     if (col == 0)
  337.         clrtoeol();
  338.     if (flg)
  339.         standend();
  340.     }
  341.     wrefresh(stdscr);
  342.     wmove(win, y, x);
  343. }
  344.  
  345. static void
  346. wgetch_wrap(WINDOW *win, int first_y)
  347. {
  348.     int last_y = getmaxy(win) - 1;
  349.     int y = getcury(win) + 1;
  350.  
  351.     if (y >= last_y)
  352.     y = first_y;
  353.     wmove(win, y, 0);
  354.     wclrtoeol(win);
  355. }
  356.  
  357. #if defined(NCURSES_VERSION) && defined(KEY_RESIZE) && HAVE_WRESIZE
  358. typedef struct {
  359.     WINDOW *text;
  360.     WINDOW *frame;
  361. } WINSTACK;
  362.  
  363. static WINSTACK *winstack = 0;
  364. static unsigned len_winstack = 0;
  365.  
  366. static void
  367. remember_boxes(unsigned level, WINDOW *txt_win, WINDOW *box_win)
  368. {
  369.     unsigned need = (level + 1) * 2;
  370.  
  371.     if (winstack == 0) {
  372.     len_winstack = 20;
  373.     winstack = malloc(len_winstack * sizeof(WINSTACK));
  374.     } else if (need >= len_winstack) {
  375.     len_winstack = need;
  376.     winstack = realloc(winstack, len_winstack * sizeof(WINSTACK));
  377.     }
  378.     winstack[level].text = txt_win;
  379.     winstack[level].frame = box_win;
  380. }
  381.  
  382. /*
  383.  * For wgetch_test(), we create pairs of windows - one for a box, one for text.
  384.  * Resize both and paint the box in the parent.
  385.  */
  386. static void
  387. resize_boxes(int level, WINDOW *win)
  388. {
  389.     unsigned n;
  390.     int base = 5;
  391.     int high = LINES - base;
  392.     int wide = COLS;
  393.  
  394.     touchwin(stdscr);
  395.     wnoutrefresh(stdscr);
  396.  
  397.     /* FIXME: this chunk should be done in resizeterm() */
  398.     slk_touch();
  399.     slk_clear();
  400.     slk_noutrefresh();
  401.  
  402.     for (n = 0; (int) n < level; ++n) {
  403.     wresize(winstack[n].frame, high, wide);
  404.     wresize(winstack[n].text, high - 2, wide - 2);
  405.     high -= 2;
  406.     wide -= 2;
  407.     werase(winstack[n].text);
  408.     box(winstack[n].frame, 0, 0);
  409.     wnoutrefresh(winstack[n].frame);
  410.     wprintw(winstack[n].text,
  411.         "size %dx%d\n",
  412.         getmaxy(winstack[n].text),
  413.         getmaxx(winstack[n].text));
  414.     wnoutrefresh(winstack[n].text);
  415.     if (winstack[n].text == win)
  416.         break;
  417.     }
  418.     doupdate();
  419. }
  420. #else
  421. #define remember_boxes(level,text,frame)    /* nothing */
  422. #endif
  423.  
  424. static void
  425. wgetch_test(int level, WINDOW *win, int delay)
  426. {
  427.     char buf[BUFSIZ];
  428.     int first_y, first_x;
  429.     int c;
  430.     int incount = 0;
  431.     bool flags[256];
  432.     bool blocking = (delay < 0);
  433.     int y, x;
  434.  
  435.     memset(flags, FALSE, sizeof(flags));
  436.     flags['k'] = (win == stdscr);
  437.  
  438.     setup_getch(win, flags);
  439.     wtimeout(win, delay);
  440.     getyx(win, first_y, first_x);
  441.  
  442.     wgetch_help(win, flags);
  443.     wsetscrreg(win, first_y, getmaxy(win) - 1);
  444.     scrollok(win, TRUE);
  445.  
  446.     for (;;) {
  447.     while ((c = wGetchar(win)) == ERR) {
  448.         incount++;
  449.         if (blocking) {
  450.         (void) wprintw(win, "%05d: input error", incount);
  451.         break;
  452.         } else {
  453.         (void) wprintw(win, "%05d: input timed out", incount);
  454.         }
  455.         wgetch_wrap(win, first_y);
  456.     }
  457.     if (c == ERR && blocking) {
  458.         wprintw(win, "ERR");
  459.         wgetch_wrap(win, first_y);
  460.     } else if (c == 'x' || c == 'q') {
  461.         break;
  462.     } else if (c == 'e') {
  463.         flags['e'] = !flags['e'];
  464.         setup_getch(win, flags);
  465.         wgetch_help(win, flags);
  466.     } else if (c == 'g') {
  467.         waddstr(win, "getstr test: ");
  468.         echo();
  469.         wgetnstr(win, buf, sizeof(buf) - 1);
  470.         noecho();
  471.         wprintw(win, "I saw %d characters:\n\t`%s'.", (int) strlen(buf), buf);
  472.         wclrtoeol(win);
  473.         wgetch_wrap(win, first_y);
  474.     } else if (c == 'k') {
  475.         flags['k'] = !flags['k'];
  476.         setup_getch(win, flags);
  477.         wgetch_help(win, flags);
  478.     } else if (c == 'm') {
  479.         flags['m'] = !flags['m'];
  480.         setup_getch(win, flags);
  481.         wgetch_help(win, flags);
  482.     } else if (c == 's') {
  483.         ShellOut(TRUE);
  484.     } else if (c == 'w') {
  485.         int high = getmaxy(win) - 1 - first_y + 1;
  486.         int wide = getmaxx(win) - first_x;
  487.         int old_y, old_x;
  488.         int new_y = first_y + getbegy(win);
  489.         int new_x = first_x + getbegx(win);
  490.  
  491.         getyx(win, old_y, old_x);
  492.         if (high > 2 && wide > 2) {
  493.         WINDOW *wb = newwin(high, wide, new_y, new_x);
  494.         WINDOW *wi = newwin(high - 2, wide - 2, new_y + 1, new_x + 1);
  495.  
  496.         box(wb, 0, 0);
  497.         wrefresh(wb);
  498.         wmove(wi, 0, 0);
  499.         remember_boxes(level, wi, wb);
  500.         wgetch_test(level + 1, wi, delay);
  501.         delwin(wi);
  502.         delwin(wb);
  503.  
  504.         wgetch_help(win, flags);
  505.         wmove(win, old_y, old_x);
  506.         touchwin(win);
  507.         wrefresh(win);
  508.         doupdate();
  509.         }
  510. #ifdef SIGTSTP
  511.     } else if (c == 'z') {
  512.         kill(getpid(), SIGTSTP);
  513. #endif
  514.     } else {
  515.         wprintw(win, "Key pressed: %04o ", c);
  516. #ifdef NCURSES_MOUSE_VERSION
  517.         if (c == KEY_MOUSE) {
  518.         MEVENT event;
  519.  
  520.         getmouse(&event);
  521.         wprintw(win, "KEY_MOUSE, %s", mouse_decode(&event));
  522.         getyx(win, y, x);
  523.         move(event.y, event.x);
  524.         addch('*');
  525.         wmove(win, y, x);
  526.         } else
  527. #endif /* NCURSES_MOUSE_VERSION */
  528.         if (c >= KEY_MIN) {
  529. #if defined(NCURSES_VERSION) && defined(KEY_RESIZE) && HAVE_WRESIZE
  530.         if (c == KEY_RESIZE) {
  531.             resize_boxes(level, win);
  532.         }
  533. #endif
  534.         (void) waddstr(win, keyname(c));
  535.         } else if (c > 0x80) {
  536.         int c2 = (c & 0x7f);
  537.         if (isprint(c2))
  538.             (void) wprintw(win, "M-%c", c2);
  539.         else
  540.             (void) wprintw(win, "M-%s", unctrl(c2));
  541.         waddstr(win, " (high-half character)");
  542.         } else {
  543.         if (isprint(c))
  544.             (void) wprintw(win, "%c (ASCII printable character)", c);
  545.         else
  546.             (void) wprintw(win, "%s (ASCII control character)",
  547.                    unctrl(c));
  548.         }
  549.         wgetch_wrap(win, first_y);
  550.     }
  551.     }
  552.  
  553.     wtimeout(win, -1);
  554. }
  555.  
  556. static int
  557. begin_getch_test(void)
  558. {
  559.     char buf[BUFSIZ];
  560.     int delay;
  561.  
  562.     refresh();
  563.  
  564. #ifdef NCURSES_MOUSE_VERSION
  565.     mousemask(ALL_MOUSE_EVENTS, (mmask_t *) 0);
  566. #endif
  567.  
  568.     (void) printw("Delay in 10ths of a second (<CR> for blocking input)? ");
  569.     echo();
  570.     getnstr(buf, sizeof(buf) - 1);
  571.     noecho();
  572.     nonl();
  573.  
  574.     if (isdigit(UChar(buf[0]))) {
  575.     delay = atoi(buf) * 100;
  576.     } else {
  577.     delay = -1;
  578.     }
  579.     raw();
  580.     move(5, 0);
  581.     return delay;
  582. }
  583.  
  584. static void
  585. finish_getch_test(void)
  586. {
  587. #ifdef NCURSES_MOUSE_VERSION
  588.     mousemask(0, (mmask_t *) 0);
  589. #endif
  590.     erase();
  591.     noraw();
  592.     nl();
  593.     endwin();
  594. }
  595.  
  596. static void
  597. getch_test(void)
  598. {
  599.     int delay = begin_getch_test();
  600.     wgetch_test(0, stdscr, delay);
  601.     finish_getch_test();
  602. }
  603.  
  604. #if USE_WIDEC_SUPPORT
  605. /*
  606.  * For wgetch_test(), we create pairs of windows - one for a box, one for text.
  607.  * Resize both and paint the box in the parent.
  608.  */
  609. static void
  610. resize_wide_boxes(int level, WINDOW *win)
  611. {
  612.     unsigned n;
  613.     int base = 5;
  614.     int high = LINES - base;
  615.     int wide = COLS;
  616.  
  617.     touchwin(stdscr);
  618.     wnoutrefresh(stdscr);
  619.  
  620.     /* FIXME: this chunk should be done in resizeterm() */
  621.     slk_touch();
  622.     slk_clear();
  623.     slk_noutrefresh();
  624.  
  625.     for (n = 0; (int) n < level; ++n) {
  626.     wresize(winstack[n].frame, high, wide);
  627.     wresize(winstack[n].text, high - 2, wide - 2);
  628.     high -= 2;
  629.     wide -= 2;
  630.     werase(winstack[n].text);
  631.     box_set(winstack[n].frame, 0, 0);
  632.     wnoutrefresh(winstack[n].frame);
  633.     wprintw(winstack[n].text,
  634.         "size %dx%d\n",
  635.         getmaxy(winstack[n].text),
  636.         getmaxx(winstack[n].text));
  637.     wnoutrefresh(winstack[n].text);
  638.     if (winstack[n].text == win)
  639.         break;
  640.     }
  641.     doupdate();
  642. }
  643.  
  644. static void
  645. wget_wch_test(int level, WINDOW *win, int delay)
  646. {
  647.     char buf[BUFSIZ];
  648.     int first_y, first_x;
  649.     wint_t c;
  650.     int incount = 0;
  651.     bool flags[256];
  652.     bool blocking = (delay < 0);
  653.     int y, x, code;
  654.  
  655.     memset(flags, FALSE, sizeof(flags));
  656.     flags['k'] = (win == stdscr);
  657.  
  658.     setup_getch(win, flags);
  659.     wtimeout(win, delay);
  660.     getyx(win, first_y, first_x);
  661.  
  662.     wgetch_help(win, flags);
  663.     wsetscrreg(win, first_y, getmaxy(win) - 1);
  664.     scrollok(win, TRUE);
  665.  
  666.     for (;;) {
  667.     while ((code = wGet_wchar(win, &c)) == ERR) {
  668.         incount++;
  669.         if (blocking) {
  670.         (void) wprintw(win, "%05d: input error", incount);
  671.         break;
  672.         } else {
  673.         (void) wprintw(win, "%05d: input timed out", incount);
  674.         }
  675.         wgetch_wrap(win, first_y);
  676.     }
  677.     if (code == ERR && blocking) {
  678.         wprintw(win, "ERR");
  679.         wgetch_wrap(win, first_y);
  680.     } else if (c == 'x' || c == 'q') {
  681.         break;
  682.     } else if (c == 'e') {
  683.         flags['e'] = !flags['e'];
  684.         setup_getch(win, flags);
  685.         wgetch_help(win, flags);
  686.     } else if (c == 'g') {
  687.         waddstr(win, "getstr test: ");
  688.         echo();
  689.         wgetnstr(win, buf, sizeof(buf) - 1);
  690.         noecho();
  691.         wprintw(win, "I saw %d characters:\n\t`%s'.", strlen(buf), buf);
  692.         wclrtoeol(win);
  693.         wgetch_wrap(win, first_y);
  694.     } else if (c == 'k') {
  695.         flags['k'] = !flags['k'];
  696.         setup_getch(win, flags);
  697.         wgetch_help(win, flags);
  698.     } else if (c == 'm') {
  699.         flags['m'] = !flags['m'];
  700.         setup_getch(win, flags);
  701.         wgetch_help(win, flags);
  702.     } else if (c == 's') {
  703.         ShellOut(TRUE);
  704.     } else if (c == 'w') {
  705.         int high = getmaxy(win) - 1 - first_y + 1;
  706.         int wide = getmaxx(win) - first_x;
  707.         int old_y, old_x;
  708.         int new_y = first_y + getbegy(win);
  709.         int new_x = first_x + getbegx(win);
  710.  
  711.         getyx(win, old_y, old_x);
  712.         if (high > 2 && wide > 2) {
  713.         WINDOW *wb = newwin(high, wide, new_y, new_x);
  714.         WINDOW *wi = newwin(high - 2, wide - 2, new_y + 1, new_x + 1);
  715.  
  716.         box_set(wb, 0, 0);
  717.         wrefresh(wb);
  718.         wmove(wi, 0, 0);
  719.         remember_boxes(level, wi, wb);
  720.         wget_wch_test(level + 1, wi, delay);
  721.         delwin(wi);
  722.         delwin(wb);
  723.  
  724.         wgetch_help(win, flags);
  725.         wmove(win, old_y, old_x);
  726.         touchwin(win);
  727.         wrefresh(win);
  728.         }
  729. #ifdef SIGTSTP
  730.     } else if (c == 'z') {
  731.         kill(getpid(), SIGTSTP);
  732. #endif
  733.     } else {
  734.         wprintw(win, "Key pressed: %04o ", c);
  735. #ifdef NCURSES_MOUSE_VERSION
  736.         if (c == KEY_MOUSE) {
  737.         MEVENT event;
  738.  
  739.         getmouse(&event);
  740.         wprintw(win, "KEY_MOUSE, %s", mouse_decode(&event));
  741.         getyx(win, y, x);
  742.         move(event.y, event.x);
  743.         addch('*');
  744.         wmove(win, y, x);
  745.         } else
  746. #endif /* NCURSES_MOUSE_VERSION */
  747.         if (code == KEY_CODE_YES) {
  748. #ifdef KEY_RESIZE
  749.         if (c == KEY_RESIZE) {
  750.             resize_wide_boxes(level, win);
  751.         }
  752. #endif
  753.         (void) waddstr(win, key_name(c));
  754.         } else {
  755.         if (c < 256 && iscntrl(c)) {
  756.             (void) wprintw(win, "%s (control character)", unctrl(c));
  757.         } else {
  758.             wchar_t c2 = c;
  759.             waddnwstr(win, &c2, 1);
  760.             (void) wprintw(win, " = %#x (printable character)", c);
  761.         }
  762.         }
  763.         wgetch_wrap(win, first_y);
  764.     }
  765.     }
  766.  
  767.     wtimeout(win, -1);
  768. }
  769.  
  770. static void
  771. get_wch_test(void)
  772. {
  773.     int delay = begin_getch_test();
  774.     wget_wch_test(0, stdscr, delay);
  775.     finish_getch_test();
  776. }
  777. #endif
  778.  
  779. /****************************************************************************
  780.  *
  781.  * Character attributes test
  782.  *
  783.  ****************************************************************************/
  784.  
  785. static int
  786. show_attr(int row, int skip, chtype attr, const char *name)
  787. {
  788.     static const char *string = "abcde fghij klmno pqrst uvwxy z";
  789.     int ncv = tigetnum("ncv");
  790.  
  791.     mvprintw(row, 8, "%s mode:", name);
  792.     mvprintw(row, 24, "|");
  793.     if (skip)
  794.     printw("%*s", skip, " ");
  795.     attrset(attr);
  796.     /*
  797.      * If we're to write a string in the alternate character set, it is not
  798.      * sufficient to just set A_ALTCHARSET.  We have to perform the mapping
  799.      * that corresponds.  This is not needed for vt100-compatible devices
  800.      * because the acs_map[] is 1:1, but for PC-style devices such as Linux
  801.      * console, the acs_map[] is scattered about the range.
  802.      *
  803.      * The addch/addstr functions do not themselves do this mapping, since it
  804.      * is possible to turn off the A_ALTCHARSET flag for the characters which
  805.      * are added, and it would be an unexpected result to have the mapped
  806.      * characters visible on the screen.
  807.      *
  808.      * This example works because the indices into acs_map[] are mostly from
  809.      * the lowercase characters.
  810.      */
  811.     if (attr & A_ALTCHARSET) {
  812.     const char *s = string;
  813.     while (*s) {
  814.         int ch = *s++;
  815. #ifdef CURSES_ACS_ARRAY
  816.         if ((ch = CURSES_ACS_ARRAY[ch]) == 0)
  817.         ch = ' ';
  818. #endif
  819.         addch(ch);
  820.     }
  821.     } else {
  822.     addstr(string);
  823.     }
  824.     attroff(attr);
  825.     if (skip)
  826.     printw("%*s", skip, " ");
  827.     printw("|");
  828.     if (attr != A_NORMAL) {
  829.     if (!(termattrs() & attr)) {
  830.         printw(" (N/A)");
  831.     } else if (ncv > 0 && (getbkgd(stdscr) & A_COLOR)) {
  832.         static const chtype table[] =
  833.         {
  834.         A_STANDOUT,
  835.         A_UNDERLINE,
  836.         A_REVERSE,
  837.         A_BLINK,
  838.         A_DIM,
  839.         A_BOLD,
  840.         A_INVIS,
  841.         A_PROTECT,
  842.         A_ALTCHARSET
  843.         };
  844.         unsigned n;
  845.         bool found = FALSE;
  846.         for (n = 0; n < SIZEOF(table); n++) {
  847.         if ((table[n] & attr) != 0
  848.             && ((1 << n) & ncv) != 0) {
  849.             found = TRUE;
  850.             break;
  851.         }
  852.         }
  853.         if (found)
  854.         printw(" (NCV)");
  855.     }
  856.     }
  857.     return row + 2;
  858. }
  859.  
  860. static bool
  861. attr_getc(int *skip, int *fg, int *bg, int *ac)
  862. {
  863.     int ch = Getchar();
  864.  
  865.     if (isdigit(ch)) {
  866.     *skip = (ch - '0');
  867.     } else if (ch == CTRL('L')) {
  868.     touchwin(stdscr);
  869.     touchwin(curscr);
  870.     } else if (has_colors()) {
  871.     switch (ch) {
  872.     case 'a':
  873.         *ac = 0;
  874.         break;
  875.     case 'A':
  876.         *ac = A_ALTCHARSET;
  877.         break;
  878.     case 'f':
  879.         *fg = (*fg + 1);
  880.         break;
  881.     case 'F':
  882.         *fg = (*fg - 1);
  883.         break;
  884.     case 'b':
  885.         *bg = (*bg + 1);
  886.         break;
  887.     case 'B':
  888.         *bg = (*bg - 1);
  889.         break;
  890.     default:
  891.         return FALSE;
  892.     }
  893.     if (*fg >= max_colors)
  894.         *fg = 0;
  895.     if (*fg < 0)
  896.         *fg = max_colors - 1;
  897.     if (*bg >= max_colors)
  898.         *bg = 0;
  899.     if (*bg < 0)
  900.         *bg = max_colors - 1;
  901.     } else {
  902.     switch (ch) {
  903.     case 'a':
  904.         *ac = 0;
  905.         break;
  906.     case 'A':
  907.         *ac = A_ALTCHARSET;
  908.         break;
  909.     default:
  910.         return FALSE;
  911.     }
  912.     }
  913.     return TRUE;
  914. }
  915.  
  916. static void
  917. attr_test(void)
  918. /* test text attributes */
  919. {
  920.     int n;
  921.     int skip = tigetnum("xmc");
  922.     int fg = COLOR_BLACK;    /* color pair 0 is special */
  923.     int bg = COLOR_BLACK;
  924.     int ac = 0;
  925.     bool *pairs = (bool *) calloc(max_pairs, sizeof(bool));
  926.     pairs[0] = TRUE;
  927.  
  928.     if (skip < 0)
  929.     skip = 0;
  930.  
  931.     n = skip;            /* make it easy */
  932.  
  933.     do {
  934.     int row = 2;
  935.     int normal = A_NORMAL | BLANK;
  936.  
  937.     if (has_colors()) {
  938.         int pair = (fg * max_colors) + bg;
  939.         if (!pairs[pair]) {
  940.         init_pair(pair, fg, bg);
  941.         pairs[pair] = TRUE;
  942.         }
  943.         normal |= COLOR_PAIR(pair);
  944.     }
  945.     bkgd(normal);
  946.     bkgdset(normal);
  947.     erase();
  948.  
  949.     box(stdscr, 0, 0);
  950.     mvaddstr(0, 20, "Character attribute test display");
  951.  
  952.     row = show_attr(row, n, ac | A_STANDOUT, "STANDOUT");
  953.     row = show_attr(row, n, ac | A_REVERSE, "REVERSE");
  954.     row = show_attr(row, n, ac | A_BOLD, "BOLD");
  955.     row = show_attr(row, n, ac | A_UNDERLINE, "UNDERLINE");
  956.     row = show_attr(row, n, ac | A_DIM, "DIM");
  957.     row = show_attr(row, n, ac | A_BLINK, "BLINK");
  958.     row = show_attr(row, n, ac | A_PROTECT, "PROTECT");
  959.     row = show_attr(row, n, ac | A_INVIS, "INVISIBLE");
  960.     row = show_attr(row, n, ac | A_NORMAL, "NORMAL");
  961.  
  962.     mvprintw(row, 8,
  963.          "This terminal does %shave the magic-cookie glitch",
  964.          tigetnum("xmc") > -1 ? "" : "not ");
  965.     mvprintw(row + 1, 8,
  966.          "Enter a digit to set gaps on each side of displayed attributes");
  967.     mvprintw(row + 2, 8,
  968.          "^L = repaint");
  969.     if (has_colors())
  970.         printw(".  f/F/b/F toggle colors (now %d/%d), a/A altcharset (%d)",
  971.            fg, bg, ac != 0);
  972.     else
  973.         printw(".  a/A altcharset (%d)", ac != 0);
  974.  
  975.     refresh();
  976.     } while (attr_getc(&n, &fg, &bg, &ac));
  977.  
  978.     free((char *) pairs);
  979.     bkgdset(A_NORMAL | BLANK);
  980.     erase();
  981.     endwin();
  982. }
  983.  
  984. /****************************************************************************
  985.  *
  986.  * Color support tests
  987.  *
  988.  ****************************************************************************/
  989.  
  990. static NCURSES_CONST char *the_color_names[] =
  991. {
  992.     "black",
  993.     "red",
  994.     "green",
  995.     "yellow",
  996.     "blue",
  997.     "magenta",
  998.     "cyan",
  999.     "white",
  1000.     "BLACK",
  1001.     "RED",
  1002.     "GREEN",
  1003.     "YELLOW",
  1004.     "BLUE",
  1005.     "MAGENTA",
  1006.     "CYAN",
  1007.     "WHITE"
  1008. };
  1009.  
  1010. static void
  1011. show_color_name(int y, int x, int color)
  1012. {
  1013.     if (max_colors > 8)
  1014.     mvprintw(y, x, "%02d   ", color);
  1015.     else
  1016.     mvaddstr(y, x, the_color_names[color]);
  1017. }
  1018.  
  1019. static void
  1020. color_test(void)
  1021. /* generate a color test pattern */
  1022. {
  1023.     int i;
  1024.     int base, top, width;
  1025.     NCURSES_CONST char *hello;
  1026.  
  1027.     refresh();
  1028.     (void) printw("There are %d color pairs\n", COLOR_PAIRS);
  1029.  
  1030.     width = (max_colors > 8) ? 4 : 8;
  1031.     hello = (max_colors > 8) ? "Test" : "Hello";
  1032.  
  1033.     for (base = 0; base < 2; base++) {
  1034.     top = (max_colors > 8) ? 0 : base * (max_colors + 3);
  1035.     clrtobot();
  1036.     (void) mvprintw(top + 1, 0,
  1037.             "%dx%d matrix of foreground/background colors, bright *%s*\n",
  1038.             max_colors, max_colors,
  1039.             base ? "on" : "off");
  1040.     for (i = 0; i < max_colors; i++)
  1041.         show_color_name(top + 2, (i + 1) * width, i);
  1042.     for (i = 0; i < max_colors; i++)
  1043.         show_color_name(top + 3 + i, 0, i);
  1044.     for (i = 1; i < max_pairs; i++) {
  1045.         init_pair(i, i % max_colors, i / max_colors);
  1046.         attron((attr_t) COLOR_PAIR(i));
  1047.         if (base)
  1048.         attron((attr_t) A_BOLD);
  1049.         mvaddstr(top + 3 + (i / max_colors), (i % max_colors + 1) *
  1050.              width, hello);
  1051.         attrset(A_NORMAL);
  1052.     }
  1053.     if ((max_colors > 8) || base)
  1054.         Pause();
  1055.     }
  1056.  
  1057.     erase();
  1058.     endwin();
  1059. }
  1060.  
  1061. static void
  1062. change_color(int current, int field, int value, int usebase)
  1063. {
  1064.     short red, green, blue;
  1065.  
  1066.     if (usebase)
  1067.     color_content(current, &red, &green, &blue);
  1068.     else
  1069.     red = green = blue = 0;
  1070.  
  1071.     switch (field) {
  1072.     case 0:
  1073.     red += value;
  1074.     break;
  1075.     case 1:
  1076.     green += value;
  1077.     break;
  1078.     case 2:
  1079.     blue += value;
  1080.     break;
  1081.     }
  1082.  
  1083.     if (init_color(current, red, green, blue) == ERR)
  1084.     beep();
  1085. }
  1086.  
  1087. static void
  1088. color_edit(void)
  1089. /* display the color test pattern, without trying to edit colors */
  1090. {
  1091.     int i, this_c = 0, value = 0, current = 0, field = 0;
  1092.     int last_c;
  1093.  
  1094.     refresh();
  1095.  
  1096.     for (i = 0; i < max_colors; i++)
  1097.     init_pair(i, COLOR_WHITE, i);
  1098.  
  1099.     mvprintw(LINES - 2, 0, "Number: %d", value);
  1100.  
  1101.     do {
  1102.     short red, green, blue;
  1103.  
  1104.     attron(A_BOLD);
  1105.     mvaddstr(0, 20, "Color RGB Value Editing");
  1106.     attroff(A_BOLD);
  1107.  
  1108.     for (i = 0; i < max_colors; i++) {
  1109.         mvprintw(2 + i, 0, "%c %-8s:",
  1110.              (i == current ? '>' : ' '),
  1111.              (i < (int) SIZEOF(the_color_names)
  1112.               ? the_color_names[i] : ""));
  1113.         attrset(COLOR_PAIR(i));
  1114.         addstr("        ");
  1115.         attrset(A_NORMAL);
  1116.  
  1117.         /*
  1118.          * Note: this refresh should *not* be necessary!  It works around
  1119.          * a bug in attribute handling that apparently causes the A_NORMAL
  1120.          * attribute sets to interfere with the actual emission of the
  1121.          * color setting somehow.  This needs to be fixed.
  1122.          */
  1123.         refresh();
  1124.  
  1125.         color_content(i, &red, &green, &blue);
  1126.         addstr("   R = ");
  1127.         if (current == i && field == 0)
  1128.         attron(A_STANDOUT);
  1129.         printw("%04d", red);
  1130.         if (current == i && field == 0)
  1131.         attrset(A_NORMAL);
  1132.         addstr(", G = ");
  1133.         if (current == i && field == 1)
  1134.         attron(A_STANDOUT);
  1135.         printw("%04d", green);
  1136.         if (current == i && field == 1)
  1137.         attrset(A_NORMAL);
  1138.         addstr(", B = ");
  1139.         if (current == i && field == 2)
  1140.         attron(A_STANDOUT);
  1141.         printw("%04d", blue);
  1142.         if (current == i && field == 2)
  1143.         attrset(A_NORMAL);
  1144.         attrset(A_NORMAL);
  1145.         addstr(")");
  1146.     }
  1147.  
  1148.     mvaddstr(max_colors + 3, 0,
  1149.          "Use up/down to select a color, left/right to change fields.");
  1150.     mvaddstr(max_colors + 4, 0,
  1151.          "Modify field by typing nnn=, nnn-, or nnn+.  ? for help.");
  1152.  
  1153.     move(2 + current, 0);
  1154.  
  1155.     last_c = this_c;
  1156.     this_c = Getchar();
  1157.     if (isdigit(this_c) && !isdigit(last_c))
  1158.         value = 0;
  1159.  
  1160.     switch (this_c) {
  1161.     case KEY_UP:
  1162.         current = (current == 0 ? (max_colors - 1) : current - 1);
  1163.         break;
  1164.  
  1165.     case KEY_DOWN:
  1166.         current = (current == (max_colors - 1) ? 0 : current + 1);
  1167.         break;
  1168.  
  1169.     case KEY_RIGHT:
  1170.         field = (field == 2 ? 0 : field + 1);
  1171.         break;
  1172.  
  1173.     case KEY_LEFT:
  1174.         field = (field == 0 ? 2 : field - 1);
  1175.         break;
  1176.  
  1177.     case '0':
  1178.     case '1':
  1179.     case '2':
  1180.     case '3':
  1181.     case '4':
  1182.     case '5':
  1183.     case '6':
  1184.     case '7':
  1185.     case '8':
  1186.     case '9':
  1187.         value = value * 10 + (this_c - '0');
  1188.         break;
  1189.  
  1190.     case '+':
  1191.         change_color(current, field, value, 1);
  1192.         break;
  1193.  
  1194.     case '-':
  1195.         change_color(current, field, -value, 1);
  1196.         break;
  1197.  
  1198.     case '=':
  1199.         change_color(current, field, value, 0);
  1200.         break;
  1201.  
  1202.     case '?':
  1203.         erase();
  1204.         P("                      RGB Value Editing Help");
  1205.         P("");
  1206.         P("You are in the RGB value editor.  Use the arrow keys to select one of");
  1207.         P("the fields in one of the RGB triples of the current colors; the one");
  1208.         P("currently selected will be reverse-video highlighted.");
  1209.         P("");
  1210.         P("To change a field, enter the digits of the new value; they are echoed");
  1211.         P("as entered.  Finish by typing `='.  The change will take effect instantly.");
  1212.         P("To increment or decrement a value, use the same procedure, but finish");
  1213.         P("with a `+' or `-'.");
  1214.         P("");
  1215.         P("To quit, do `x' or 'q'");
  1216.  
  1217.         Pause();
  1218.         erase();
  1219.         break;
  1220.  
  1221.     case 'x':
  1222.     case 'q':
  1223.         break;
  1224.  
  1225.     default:
  1226.         beep();
  1227.         break;
  1228.     }
  1229.     mvprintw(LINES - 2, 0, "Number: %d", value);
  1230.     clrtoeol();
  1231.     } while
  1232.     (this_c != 'x' && this_c != 'q');
  1233.  
  1234.     erase();
  1235.     endwin();
  1236. }
  1237.  
  1238. /****************************************************************************
  1239.  *
  1240.  * Soft-key label test
  1241.  *
  1242.  ****************************************************************************/
  1243.  
  1244. static void
  1245. slk_test(void)
  1246. /* exercise the soft keys */
  1247. {
  1248.     int c, fmt = 1;
  1249.     char buf[9];
  1250.  
  1251.     c = CTRL('l');
  1252.     do {
  1253.     move(0, 0);
  1254.     switch (c) {
  1255.     case CTRL('l'):
  1256.         erase();
  1257.         attron(A_BOLD);
  1258.         mvaddstr(0, 20, "Soft Key Exerciser");
  1259.         attroff(A_BOLD);
  1260.  
  1261.         move(2, 0);
  1262.         P("Available commands are:");
  1263.         P("");
  1264.         P("^L         -- refresh screen");
  1265.         P("a          -- activate or restore soft keys");
  1266.         P("d          -- disable soft keys");
  1267.         P("c          -- set centered format for labels");
  1268.         P("l          -- set left-justified format for labels");
  1269.         P("r          -- set right-justified format for labels");
  1270.         P("[12345678] -- set label; labels are numbered 1 through 8");
  1271.         P("e          -- erase stdscr (should not erase labels)");
  1272.         P("s          -- test scrolling of shortened screen");
  1273.         P("x, q       -- return to main menu");
  1274.         P("");
  1275.         P("Note: if activating the soft keys causes your terminal to");
  1276.         P("scroll up one line, your terminal auto-scrolls when anything");
  1277.         P("is written to the last screen position.  The ncurses code");
  1278.         P("does not yet handle this gracefully.");
  1279.         refresh();
  1280.         /* fall through */
  1281.  
  1282.     case 'a':
  1283.         slk_restore();
  1284.         break;
  1285.  
  1286.     case 'e':
  1287.         wclear(stdscr);
  1288.         break;
  1289.  
  1290.     case 's':
  1291.         mvprintw(20, 0, "Press Q to stop the scrolling-test: ");
  1292.         while ((c = Getchar()) != 'Q' && (c != ERR))
  1293.         addch((chtype) c);
  1294.         break;
  1295.  
  1296.     case 'd':
  1297.         slk_clear();
  1298.         break;
  1299.  
  1300.     case 'l':
  1301.         fmt = 0;
  1302.         break;
  1303.  
  1304.     case 'c':
  1305.         fmt = 1;
  1306.         break;
  1307.  
  1308.     case 'r':
  1309.         fmt = 2;
  1310.         break;
  1311.  
  1312.     case '1':
  1313.     case '2':
  1314.     case '3':
  1315.     case '4':
  1316.     case '5':
  1317.     case '6':
  1318.     case '7':
  1319.     case '8':
  1320.         (void) mvaddstr(20, 0, "Please enter the label value: ");
  1321.         echo();
  1322.         wgetnstr(stdscr, buf, 8);
  1323.         noecho();
  1324.         slk_set((c - '0'), buf, fmt);
  1325.         slk_refresh();
  1326.         move(20, 0);
  1327.         clrtoeol();
  1328.         break;
  1329.  
  1330.     case 'x':
  1331.     case 'q':
  1332.         goto done;
  1333.  
  1334.     default:
  1335.         beep();
  1336.     }
  1337.     } while
  1338.     ((c = Getchar()) != EOF);
  1339.  
  1340.   done:
  1341.     erase();
  1342.     endwin();
  1343. }
  1344.  
  1345. /****************************************************************************
  1346.  *
  1347.  * Alternate character-set stuff
  1348.  *
  1349.  ****************************************************************************/
  1350.  
  1351. /* ISO 6429:  codes 0x80 to 0x9f may be control characters that cause the
  1352.  * terminal to perform functions.  The remaining codes can be graphic.
  1353.  */
  1354. static void
  1355. show_upper_chars(int first)
  1356. {
  1357.     bool C1 = (first == 128);
  1358.     int code;
  1359.     int last = first + 31;
  1360.     int reply;
  1361.  
  1362.     erase();
  1363.     attron(A_BOLD);
  1364.     mvprintw(0, 20, "Display of %s Character Codes %d to %d",
  1365.          C1 ? "C1" : "GR", first, last);
  1366.     attroff(A_BOLD);
  1367.     refresh();
  1368.  
  1369.     for (code = first; code <= last; code++) {
  1370.     int row = 4 + ((code - first) % 16);
  1371.     int col = ((code - first) / 16) * COLS / 2;
  1372.     char tmp[80];
  1373.     sprintf(tmp, "%3d (0x%x)", code, code);
  1374.     mvprintw(row, col, "%*s: ", COLS / 4, tmp);
  1375.     if (C1)
  1376.         nodelay(stdscr, TRUE);
  1377.     echochar(code);
  1378.     if (C1) {
  1379.         /* (yes, this _is_ crude) */
  1380.         while ((reply = Getchar()) != ERR) {
  1381.         addch(reply);
  1382.         napms(10);
  1383.         }
  1384.         nodelay(stdscr, FALSE);
  1385.     }
  1386.     }
  1387. }
  1388.  
  1389. static void
  1390. show_box_chars(void)
  1391. {
  1392.     erase();
  1393.     attron(A_BOLD);
  1394.     mvaddstr(0, 20, "Display of the ACS Line-Drawing Set");
  1395.     attroff(A_BOLD);
  1396.     refresh();
  1397.     box(stdscr, 0, 0);
  1398.     /* *INDENT-OFF* */
  1399.     mvhline(LINES / 2, 0,        ACS_HLINE, COLS);
  1400.     mvvline(0,         COLS / 2, ACS_VLINE, LINES);
  1401.     mvaddch(0,         COLS / 2, ACS_TTEE);
  1402.     mvaddch(LINES / 2, COLS / 2, ACS_PLUS);
  1403.     mvaddch(LINES - 1, COLS / 2, ACS_BTEE);
  1404.     mvaddch(LINES / 2, 0,        ACS_LTEE);
  1405.     mvaddch(LINES / 2, COLS - 1, ACS_RTEE);
  1406.     /* *INDENT-ON* */
  1407.  
  1408. }
  1409.  
  1410. static int
  1411. show_1_acs(int n, const char *name, chtype code)
  1412. {
  1413.     const int height = 16;
  1414.     int row = 4 + (n % height);
  1415.     int col = (n / height) * COLS / 2;
  1416.     mvprintw(row, col, "%*s : ", COLS / 4, name);
  1417.     addch(code);
  1418.     return n + 1;
  1419. }
  1420.  
  1421. static void
  1422. show_acs_chars(void)
  1423. /* display the ACS character set */
  1424. {
  1425.     int n;
  1426.  
  1427. #define BOTH(name) #name, name
  1428.  
  1429.     erase();
  1430.     attron(A_BOLD);
  1431.     mvaddstr(0, 20, "Display of the ACS Character Set");
  1432.     attroff(A_BOLD);
  1433.     refresh();
  1434.  
  1435.     n = show_1_acs(0, BOTH(ACS_ULCORNER));
  1436.     n = show_1_acs(n, BOTH(ACS_URCORNER));
  1437.     n = show_1_acs(n, BOTH(ACS_LLCORNER));
  1438.     n = show_1_acs(n, BOTH(ACS_LRCORNER));
  1439.  
  1440.     n = show_1_acs(n, BOTH(ACS_LTEE));
  1441.     n = show_1_acs(n, BOTH(ACS_RTEE));
  1442.     n = show_1_acs(n, BOTH(ACS_TTEE));
  1443.     n = show_1_acs(n, BOTH(ACS_BTEE));
  1444.  
  1445.     n = show_1_acs(n, BOTH(ACS_HLINE));
  1446.     n = show_1_acs(n, BOTH(ACS_VLINE));
  1447.  
  1448.     n = show_1_acs(n, BOTH(ACS_LARROW));
  1449.     n = show_1_acs(n, BOTH(ACS_RARROW));
  1450.     n = show_1_acs(n, BOTH(ACS_UARROW));
  1451.     n = show_1_acs(n, BOTH(ACS_DARROW));
  1452.  
  1453.     n = show_1_acs(n, BOTH(ACS_BLOCK));
  1454.     n = show_1_acs(n, BOTH(ACS_BOARD));
  1455.     n = show_1_acs(n, BOTH(ACS_LANTERN));
  1456.     n = show_1_acs(n, BOTH(ACS_BULLET));
  1457.     n = show_1_acs(n, BOTH(ACS_CKBOARD));
  1458.     n = show_1_acs(n, BOTH(ACS_DEGREE));
  1459.     n = show_1_acs(n, BOTH(ACS_DIAMOND));
  1460.     n = show_1_acs(n, BOTH(ACS_PLMINUS));
  1461.     n = show_1_acs(n, BOTH(ACS_PLUS));
  1462.  
  1463.     n = show_1_acs(n, BOTH(ACS_GEQUAL));
  1464.     n = show_1_acs(n, BOTH(ACS_NEQUAL));
  1465.     n = show_1_acs(n, BOTH(ACS_LEQUAL));
  1466.  
  1467.     n = show_1_acs(n, BOTH(ACS_STERLING));
  1468.     n = show_1_acs(n, BOTH(ACS_PI));
  1469.     n = show_1_acs(n, BOTH(ACS_S1));
  1470.     n = show_1_acs(n, BOTH(ACS_S3));
  1471.     n = show_1_acs(n, BOTH(ACS_S7));
  1472.     n = show_1_acs(n, BOTH(ACS_S9));
  1473. }
  1474.  
  1475. static void
  1476. acs_display(void)
  1477. {
  1478.     int c = 'a';
  1479.  
  1480.     do {
  1481.     switch (c) {
  1482.     case 'a':
  1483.         show_acs_chars();
  1484.         break;
  1485.     case 'b':
  1486.         show_box_chars();
  1487.         break;
  1488.     case '0':
  1489.     case '1':
  1490.     case '2':
  1491.     case '3':
  1492.         show_upper_chars((c - '0') * 32 + 128);
  1493.         break;
  1494.     }
  1495.     mvprintw(LINES - 3, 0,
  1496.          "Note: ANSI terminals may not display C1 characters.");
  1497.     mvprintw(LINES - 2, 0,
  1498.          "Select: a=ACS, b=box, 0=C1, 1,2,3=GR characters, q=quit");
  1499.     refresh();
  1500.     } while ((c = Getchar()) != 'x' && c != 'q');
  1501.  
  1502.     Pause();
  1503.     erase();
  1504.     endwin();
  1505. }
  1506.  
  1507. #if USE_WIDEC_SUPPORT
  1508. static void
  1509. show_upper_widechars(int first)
  1510. {
  1511.     cchar_t temp;
  1512.     wchar_t code;
  1513.     int last = first + 31;
  1514.  
  1515.     erase();
  1516.     attron(A_BOLD);
  1517.     mvprintw(0, 20, "Display of Character Codes %d to %d", first, last);
  1518.     attroff(A_BOLD);
  1519.     refresh();
  1520.  
  1521.     for (code = first; code <= last; code++) {
  1522.     int row = 4 + ((code - first) % 16);
  1523.     int col = ((code - first) / 16) * COLS / 2;
  1524.     wchar_t codes[10];
  1525.     attr_t attrs = A_NORMAL;
  1526.     char tmp[80];
  1527.  
  1528.     memset(&codes, 0, sizeof(codes));
  1529.     codes[0] = code;
  1530.     sprintf(tmp, "%3ld (0x%lx)", code, code);
  1531.     mvprintw(row, col, "%*s: ", COLS / 4, tmp);
  1532.     setcchar(&temp, codes, attrs, 0, 0);
  1533.     echo_wchar(&temp);
  1534.     }
  1535. }
  1536.  
  1537. static int
  1538. show_1_wacs(int n, const char *name, const cchar_t * code)
  1539. {
  1540.     const int height = 16;
  1541.     int row = 4 + (n % height);
  1542.     int col = (n / height) * COLS / 2;
  1543.     mvprintw(row, col, "%*s : ", COLS / 4, name);
  1544.     add_wchnstr(code, 1);
  1545.     return n + 1;
  1546. }
  1547.  
  1548. static void
  1549. show_wacs_chars(void)
  1550. /* display the wide-ACS character set */
  1551. {
  1552.     int n;
  1553.  
  1554. /*#define BOTH2(name) #name, &(name) */
  1555. #define BOTH2(name) #name, name
  1556.  
  1557.     erase();
  1558.     attron(A_BOLD);
  1559.     mvaddstr(0, 20, "Display of the Wide-ACS Character Set");
  1560.     attroff(A_BOLD);
  1561.     refresh();
  1562.  
  1563.     n = show_1_wacs(0, BOTH2(WACS_ULCORNER));
  1564.     n = show_1_wacs(n, BOTH2(WACS_URCORNER));
  1565.     n = show_1_wacs(n, BOTH2(WACS_LLCORNER));
  1566.     n = show_1_wacs(n, BOTH2(WACS_LRCORNER));
  1567.  
  1568.     n = show_1_wacs(n, BOTH2(WACS_LTEE));
  1569.     n = show_1_wacs(n, BOTH2(WACS_RTEE));
  1570.     n = show_1_wacs(n, BOTH2(WACS_TTEE));
  1571.     n = show_1_wacs(n, BOTH2(WACS_BTEE));
  1572.  
  1573.     n = show_1_wacs(n, BOTH2(WACS_HLINE));
  1574.     n = show_1_wacs(n, BOTH2(WACS_VLINE));
  1575.  
  1576.     n = show_1_wacs(n, BOTH2(WACS_LARROW));
  1577.     n = show_1_wacs(n, BOTH2(WACS_RARROW));
  1578.     n = show_1_wacs(n, BOTH2(WACS_UARROW));
  1579.     n = show_1_wacs(n, BOTH2(WACS_DARROW));
  1580.  
  1581.     n = show_1_wacs(n, BOTH2(WACS_BLOCK));
  1582.     n = show_1_wacs(n, BOTH2(WACS_BOARD));
  1583.     n = show_1_wacs(n, BOTH2(WACS_LANTERN));
  1584.     n = show_1_wacs(n, BOTH2(WACS_BULLET));
  1585.     n = show_1_wacs(n, BOTH2(WACS_CKBOARD));
  1586.     n = show_1_wacs(n, BOTH2(WACS_DEGREE));
  1587.     n = show_1_wacs(n, BOTH2(WACS_DIAMOND));
  1588.     n = show_1_wacs(n, BOTH2(WACS_PLMINUS));
  1589.     n = show_1_wacs(n, BOTH2(WACS_PLUS));
  1590.  
  1591. #ifdef CURSES_WACS_ARRAY
  1592.     n = show_1_wacs(n, BOTH2(WACS_GEQUAL));
  1593.     n = show_1_wacs(n, BOTH2(WACS_NEQUAL));
  1594.     n = show_1_wacs(n, BOTH2(WACS_LEQUAL));
  1595.  
  1596.     n = show_1_wacs(n, BOTH2(WACS_STERLING));
  1597.     n = show_1_wacs(n, BOTH2(WACS_PI));
  1598.     n = show_1_wacs(n, BOTH2(WACS_S1));
  1599.     n = show_1_wacs(n, BOTH2(WACS_S3));
  1600.     n = show_1_wacs(n, BOTH2(WACS_S7));
  1601.     n = show_1_wacs(n, BOTH2(WACS_S9));
  1602. #endif
  1603. }
  1604.  
  1605. static void
  1606. show_wbox_chars(void)
  1607. {
  1608.     erase();
  1609.     attron(A_BOLD);
  1610.     mvaddstr(0, 20, "Display of the Wide-ACS Line-Drawing Set");
  1611.     attroff(A_BOLD);
  1612.     refresh();
  1613.     box_set(stdscr, 0, 0);
  1614.     /* *INDENT-OFF* */
  1615.     mvhline_set(LINES / 2, 0,        WACS_HLINE, COLS);
  1616.     mvvline_set(0,         COLS / 2, WACS_VLINE, LINES);
  1617.     mvadd_wch(0,           COLS / 2, WACS_TTEE);
  1618.     mvadd_wch(LINES / 2,   COLS / 2, WACS_PLUS);
  1619.     mvadd_wch(LINES - 1,   COLS / 2, WACS_BTEE);
  1620.     mvadd_wch(LINES / 2,   0,        WACS_LTEE);
  1621.     mvadd_wch(LINES / 2,   COLS - 1, WACS_RTEE);
  1622.     /* *INDENT-ON* */
  1623.  
  1624. }
  1625.  
  1626. static int
  1627. show_2_wacs(int n, const char *name, char *code)
  1628. {
  1629.     const int height = 16;
  1630.     int row = 4 + (n % height);
  1631.     int col = (n / height) * COLS / 2;
  1632.     mvprintw(row, col, "%*s : ", COLS / 4, name);
  1633.     addstr(code);
  1634.     return n + 1;
  1635. }
  1636.  
  1637. static void
  1638. show_utf8_chars(void)
  1639. /* display the wide-ACS character set */
  1640. {
  1641.     int n;
  1642.  
  1643.     erase();
  1644.     attron(A_BOLD);
  1645.     mvaddstr(0, 20, "Display of the Wide-ACS Character Set");
  1646.     attroff(A_BOLD);
  1647.     refresh();
  1648.     /* *INDENT-OFF* */
  1649.     n = show_2_wacs(0, "WACS_ULCORNER",    "\342\224\214");
  1650.     n = show_2_wacs(n, "WACS_URCORNER",    "\342\224\220");
  1651.     n = show_2_wacs(n, "WACS_LLCORNER",    "\342\224\224");
  1652.     n = show_2_wacs(n, "WACS_LRCORNER",    "\342\224\230");
  1653.  
  1654.     n = show_2_wacs(n, "WACS_LTEE",    "\342\224\234");
  1655.     n = show_2_wacs(n, "WACS_RTEE",    "\342\224\244");
  1656.     n = show_2_wacs(n, "WACS_TTEE",    "\342\224\254");
  1657.     n = show_2_wacs(n, "WACS_BTEE",    "\342\224\264");
  1658.  
  1659.     n = show_2_wacs(n, "WACS_HLINE",    "\342\224\200");
  1660.     n = show_2_wacs(n, "WACS_VLINE",    "\342\224\202");
  1661.  
  1662.     n = show_2_wacs(n, "WACS_LARROW",    "\342\206\220");
  1663.     n = show_2_wacs(n, "WACS_RARROW",    "\342\206\222");
  1664.     n = show_2_wacs(n, "WACS_UARROW",    "\342\206\221");
  1665.     n = show_2_wacs(n, "WACS_DARROW",    "\342\206\223");
  1666.  
  1667.     n = show_2_wacs(n, "WACS_BLOCK",    "\342\226\256");
  1668.     n = show_2_wacs(n, "WACS_BOARD",    "\342\226\222");
  1669.     n = show_2_wacs(n, "WACS_LANTERN",    "\342\230\203");
  1670.     n = show_2_wacs(n, "WACS_BULLET",    "\302\267");
  1671.     n = show_2_wacs(n, "WACS_CKBOARD",    "\342\226\222");
  1672.     n = show_2_wacs(n, "WACS_DEGREE",    "\302\260");
  1673.     n = show_2_wacs(n, "WACS_DIAMOND",    "\342\227\206");
  1674.     n = show_2_wacs(n, "WACS_PLMINUS",    "\302\261");
  1675.     n = show_2_wacs(n, "WACS_PLUS",    "\342\224\274");
  1676.     n = show_2_wacs(n, "WACS_GEQUAL",    "\342\211\245");
  1677.     n = show_2_wacs(n, "WACS_NEQUAL",    "\342\211\240");
  1678.     n = show_2_wacs(n, "WACS_LEQUAL",    "\342\211\244");
  1679.  
  1680.     n = show_2_wacs(n, "WACS_STERLING",    "\302\243");
  1681.     n = show_2_wacs(n, "WACS_PI",    "\317\200");
  1682.     n = show_2_wacs(n, "WACS_S1",    "\342\216\272");
  1683.     n = show_2_wacs(n, "WACS_S3",    "\342\216\273");
  1684.     n = show_2_wacs(n, "WACS_S7",    "\342\216\274");
  1685.     n = show_2_wacs(n, "WACS_S9",    "\342\216\275");
  1686.     /* *INDENT-OFF* */
  1687. }
  1688.  
  1689. static void
  1690. wide_acs_display(void)
  1691. {
  1692.     int c = 'a';
  1693.  
  1694.     do {
  1695.     switch (c) {
  1696.     case 'a':
  1697.         show_wacs_chars();
  1698.         break;
  1699.     case 'b':
  1700.         show_wbox_chars();
  1701.         break;
  1702.     case 'u':
  1703.         show_utf8_chars();
  1704.         break;
  1705.     default:
  1706.         if (isdigit(c))
  1707.         show_upper_widechars((c - '0') * 32 + 128);
  1708.         break;
  1709.     }
  1710.     mvprintw(LINES - 2, 0,
  1711.          "Select: a WACS, b box, u UTF-8, 0-9 non-ASCII characters, q=quit");
  1712.     refresh();
  1713.     } while ((c = Getchar()) != 'x' && c != 'q');
  1714.  
  1715.     Pause();
  1716.     erase();
  1717.     endwin();
  1718. }
  1719.  
  1720. #endif
  1721.  
  1722. /*
  1723.  * Graphic-rendition test (adapted from vttest)
  1724.  */
  1725. static void
  1726. test_sgr_attributes(void)
  1727. {
  1728.     int pass;
  1729.  
  1730.     for (pass = 0; pass < 2; pass++) {
  1731.     int normal = ((pass == 0 ? A_NORMAL : A_REVERSE)) | BLANK;
  1732.  
  1733.     /* Use non-default colors if possible to exercise bce a little */
  1734.     if (has_colors()) {
  1735.         init_pair(1, COLOR_WHITE, COLOR_BLUE);
  1736.         normal |= COLOR_PAIR(1);
  1737.     }
  1738.     bkgdset(normal);
  1739.     erase();
  1740.     mvprintw(1, 20, "Graphic rendition test pattern:");
  1741.  
  1742.     mvprintw(4, 1, "vanilla");
  1743.  
  1744. #define set_sgr(mask) bkgdset((normal^(mask)));
  1745.     set_sgr(A_BOLD);
  1746.     mvprintw(4, 40, "bold");
  1747.  
  1748.     set_sgr(A_UNDERLINE);
  1749.     mvprintw(6, 6, "underline");
  1750.  
  1751.     set_sgr(A_BOLD | A_UNDERLINE);
  1752.     mvprintw(6, 45, "bold underline");
  1753.  
  1754.     set_sgr(A_BLINK);
  1755.     mvprintw(8, 1, "blink");
  1756.  
  1757.     set_sgr(A_BLINK | A_BOLD);
  1758.     mvprintw(8, 40, "bold blink");
  1759.  
  1760.     set_sgr(A_UNDERLINE | A_BLINK);
  1761.     mvprintw(10, 6, "underline blink");
  1762.  
  1763.     set_sgr(A_BOLD | A_UNDERLINE | A_BLINK);
  1764.     mvprintw(10, 45, "bold underline blink");
  1765.  
  1766.     set_sgr(A_REVERSE);
  1767.     mvprintw(12, 1, "negative");
  1768.  
  1769.     set_sgr(A_BOLD | A_REVERSE);
  1770.     mvprintw(12, 40, "bold negative");
  1771.  
  1772.     set_sgr(A_UNDERLINE | A_REVERSE);
  1773.     mvprintw(14, 6, "underline negative");
  1774.  
  1775.     set_sgr(A_BOLD | A_UNDERLINE | A_REVERSE);
  1776.     mvprintw(14, 45, "bold underline negative");
  1777.  
  1778.     set_sgr(A_BLINK | A_REVERSE);
  1779.     mvprintw(16, 1, "blink negative");
  1780.  
  1781.     set_sgr(A_BOLD | A_BLINK | A_REVERSE);
  1782.     mvprintw(16, 40, "bold blink negative");
  1783.  
  1784.     set_sgr(A_UNDERLINE | A_BLINK | A_REVERSE);
  1785.     mvprintw(18, 6, "underline blink negative");
  1786.  
  1787.     set_sgr(A_BOLD | A_UNDERLINE | A_BLINK | A_REVERSE);
  1788.     mvprintw(18, 45, "bold underline blink negative");
  1789.  
  1790.     bkgdset(normal);
  1791.     mvprintw(LINES - 2, 1, "%s background. ", pass == 0 ? "Dark" :
  1792.          "Light");
  1793.     clrtoeol();
  1794.     Pause();
  1795.     }
  1796.  
  1797.     bkgdset(A_NORMAL | BLANK);
  1798.     erase();
  1799.     endwin();
  1800. }
  1801.  
  1802. /****************************************************************************
  1803.  *
  1804.  * Windows and scrolling tester.
  1805.  *
  1806.  ****************************************************************************/
  1807.  
  1808. #define BOTLINES    4    /* number of line stolen from screen bottom */
  1809.  
  1810. typedef struct {
  1811.     int y, x;
  1812. } pair;
  1813.  
  1814. #define FRAME struct frame
  1815. FRAME
  1816. {
  1817.     FRAME *next, *last;
  1818.     bool do_scroll;
  1819.     bool do_keypad;
  1820.     WINDOW *wind;
  1821. };
  1822.  
  1823. #ifdef NCURSES_VERSION
  1824. #define keypad_active(win) (win)->_use_keypad
  1825. #define scroll_active(win) (win)->_scroll
  1826. #else
  1827. #define keypad_active(win) FALSE
  1828. #define scroll_active(win) FALSE
  1829. #endif
  1830.  
  1831. /* We need to know if these flags are actually set, so don't look in FRAME.
  1832.  * These names are known to work with SVr4 curses as well as ncurses.  The
  1833.  * _use_keypad name does not work with Solaris 8.
  1834.  */
  1835. static bool
  1836. HaveKeypad(FRAME * curp)
  1837. {
  1838.     WINDOW *win = (curp ? curp->wind : stdscr);
  1839.     return keypad_active(win);
  1840. }
  1841.  
  1842. static bool
  1843. HaveScroll(FRAME * curp)
  1844. {
  1845.     WINDOW *win = (curp ? curp->wind : stdscr);
  1846.     return scroll_active(win);
  1847. }
  1848.  
  1849. static void
  1850. newwin_legend(FRAME * curp)
  1851. {
  1852.     static const struct {
  1853.     const char *msg;
  1854.     int code;
  1855.     } legend[] = {
  1856.     {
  1857.         "^C = create window", 0
  1858.     },
  1859.     {
  1860.         "^N = next window", 0
  1861.     },
  1862.     {
  1863.         "^P = previous window", 0
  1864.     },
  1865.     {
  1866.         "^F = scroll forward", 0
  1867.     },
  1868.     {
  1869.         "^B = scroll backward", 0
  1870.     },
  1871.     {
  1872.         "^K = keypad(%s)", 1
  1873.     },
  1874.     {
  1875.         "^S = scrollok(%s)", 2
  1876.     },
  1877.     {
  1878.         "^W = save window to file", 0
  1879.     },
  1880.     {
  1881.         "^R = restore window", 0
  1882.     },
  1883. #if HAVE_WRESIZE
  1884.     {
  1885.         "^X = resize", 0
  1886.     },
  1887. #endif
  1888.     {
  1889.         "^Q%s = exit", 3
  1890.     }
  1891.     };
  1892.     size_t n;
  1893.     int x;
  1894.     bool do_keypad = HaveKeypad(curp);
  1895.     bool do_scroll = HaveScroll(curp);
  1896.     char buf[BUFSIZ];
  1897.  
  1898.     move(LINES - 4, 0);
  1899.     for (n = 0; n < SIZEOF(legend); n++) {
  1900.     switch (legend[n].code) {
  1901.     default:
  1902.         strcpy(buf, legend[n].msg);
  1903.         break;
  1904.     case 1:
  1905.         sprintf(buf, legend[n].msg, do_keypad ? "yes" : "no");
  1906.         break;
  1907.     case 2:
  1908.         sprintf(buf, legend[n].msg, do_scroll ? "yes" : "no");
  1909.         break;
  1910.     case 3:
  1911.         sprintf(buf, legend[n].msg, do_keypad ? "/ESC" : "");
  1912.         break;
  1913.     }
  1914.     x = getcurx(stdscr);
  1915.     addstr((COLS < (x + 3 + (int) strlen(buf))) ? "\n" : (n ? ", " : ""));
  1916.     addstr(buf);
  1917.     }
  1918.     clrtoeol();
  1919. }
  1920.  
  1921. static void
  1922. transient(FRAME * curp, NCURSES_CONST char *msg)
  1923. {
  1924.     newwin_legend(curp);
  1925.     if (msg) {
  1926.     mvaddstr(LINES - 1, 0, msg);
  1927.     refresh();
  1928.     napms(1000);
  1929.     }
  1930.  
  1931.     move(LINES - 1, 0);
  1932.     printw("%s characters are echoed, window should %sscroll.",
  1933.        HaveKeypad(curp) ? "Non-arrow" : "All other",
  1934.        HaveScroll(curp) ? "" : "not ");
  1935.     clrtoeol();
  1936. }
  1937.  
  1938. static void
  1939. newwin_report(FRAME * curp)
  1940. /* report on the cursor's current position, then restore it */
  1941. {
  1942.     WINDOW *win = (curp != 0) ? curp->wind : stdscr;
  1943.     int y, x;
  1944.  
  1945.     if (win != stdscr)
  1946.     transient(curp, (char *) 0);
  1947.     getyx(win, y, x);
  1948.     move(LINES - 1, COLS - 17);
  1949.     printw("Y = %2d X = %2d", y, x);
  1950.     if (win != stdscr)
  1951.     refresh();
  1952.     else
  1953.     wmove(win, y, x);
  1954. }
  1955.  
  1956. static pair *
  1957. selectcell(int uli, int ulj, int lri, int lrj)
  1958. /* arrows keys move cursor, return location at current on non-arrow key */
  1959. {
  1960.     static pair res;        /* result cell */
  1961.     int si = lri - uli + 1;    /* depth of the select area */
  1962.     int sj = lrj - ulj + 1;    /* width of the select area */
  1963.     int i = 0, j = 0;        /* offsets into the select area */
  1964.  
  1965.     res.y = uli;
  1966.     res.x = ulj;
  1967.     for (;;) {
  1968.     move(uli + i, ulj + j);
  1969.     newwin_report((FRAME *) 0);
  1970.  
  1971.     switch (Getchar()) {
  1972.     case KEY_UP:
  1973.         i += si - 1;
  1974.         break;
  1975.     case KEY_DOWN:
  1976.         i++;
  1977.         break;
  1978.     case KEY_LEFT:
  1979.         j += sj - 1;
  1980.         break;
  1981.     case KEY_RIGHT:
  1982.         j++;
  1983.         break;
  1984.     case QUIT:
  1985.     case ESCAPE:
  1986.         return ((pair *) 0);
  1987. #ifdef NCURSES_MOUSE_VERSION
  1988.     case KEY_MOUSE:
  1989.         {
  1990.         MEVENT event;
  1991.  
  1992.         getmouse(&event);
  1993.         if (event.y > uli && event.x > ulj) {
  1994.             i = event.y - uli;
  1995.             j = event.x - ulj;
  1996.         } else {
  1997.             beep();
  1998.             break;
  1999.         }
  2000.         }
  2001.         /* FALLTHRU */
  2002. #endif
  2003.     default:
  2004.         res.y = uli + i;
  2005.         res.x = ulj + j;
  2006.         return (&res);
  2007.     }
  2008.     i %= si;
  2009.     j %= sj;
  2010.     }
  2011. }
  2012.  
  2013. static void
  2014. outerbox(pair ul, pair lr, bool onoff)
  2015. /* draw or erase a box *outside* the given pair of corners */
  2016. {
  2017.     mvaddch(ul.y - 1, lr.x - 1, onoff ? ACS_ULCORNER : ' ');
  2018.     mvaddch(ul.y - 1, lr.x + 1, onoff ? ACS_URCORNER : ' ');
  2019.     mvaddch(lr.y + 1, lr.x + 1, onoff ? ACS_LRCORNER : ' ');
  2020.     mvaddch(lr.y + 1, ul.x - 1, onoff ? ACS_LLCORNER : ' ');
  2021.     move(ul.y - 1, ul.x);
  2022.     hline(onoff ? ACS_HLINE : ' ', lr.x - ul.x + 1);
  2023.     move(ul.y, ul.x - 1);
  2024.     vline(onoff ? ACS_VLINE : ' ', lr.y - ul.y + 1);
  2025.     move(lr.y + 1, ul.x);
  2026.     hline(onoff ? ACS_HLINE : ' ', lr.x - ul.x + 1);
  2027.     move(ul.y, lr.x + 1);
  2028.     vline(onoff ? ACS_VLINE : ' ', lr.y - ul.y + 1);
  2029. }
  2030.  
  2031. static WINDOW *
  2032. getwindow(void)
  2033. /* Ask user for a window definition */
  2034. {
  2035.     WINDOW *rwindow;
  2036.     pair ul, lr, *tmp;
  2037.  
  2038.     move(0, 0);
  2039.     clrtoeol();
  2040.     addstr("Use arrows to move cursor, anything else to mark corner 1");
  2041.     refresh();
  2042.     if ((tmp = selectcell(2, 1, LINES - BOTLINES - 2, COLS - 2)) == (pair *) 0)
  2043.     return ((WINDOW *) 0);
  2044.     memcpy(&ul, tmp, sizeof(pair));
  2045.     mvaddch(ul.y - 1, ul.x - 1, ACS_ULCORNER);
  2046.     move(0, 0);
  2047.     clrtoeol();
  2048.     addstr("Use arrows to move cursor, anything else to mark corner 2");
  2049.     refresh();
  2050.     if ((tmp = selectcell(ul.y, ul.x, LINES - BOTLINES - 2, COLS - 2)) ==
  2051.     (pair *) 0)
  2052.     return ((WINDOW *) 0);
  2053.     memcpy(&lr, tmp, sizeof(pair));
  2054.  
  2055.     rwindow = subwin(stdscr, lr.y - ul.y + 1, lr.x - ul.x + 1, ul.y, ul.x);
  2056.  
  2057.     outerbox(ul, lr, TRUE);
  2058.     refresh();
  2059.  
  2060.     wrefresh(rwindow);
  2061.  
  2062.     move(0, 0);
  2063.     clrtoeol();
  2064.     return (rwindow);
  2065. }
  2066.  
  2067. static void
  2068. newwin_move(FRAME * curp, int dy, int dx)
  2069. {
  2070.     WINDOW *win = (curp != 0) ? curp->wind : stdscr;
  2071.     int cur_y, cur_x;
  2072.     int max_y, max_x;
  2073.  
  2074.     getyx(win, cur_y, cur_x);
  2075.     getmaxyx(win, max_y, max_x);
  2076.     if ((cur_x += dx) < 0)
  2077.     cur_x = 0;
  2078.     else if (cur_x >= max_x)
  2079.     cur_x = max_x - 1;
  2080.     if ((cur_y += dy) < 0)
  2081.     cur_y = 0;
  2082.     else if (cur_y >= max_y)
  2083.     cur_y = max_y - 1;
  2084.     wmove(win, cur_y, cur_x);
  2085. }
  2086.  
  2087. static FRAME *
  2088. delete_framed(FRAME * fp, bool showit)
  2089. {
  2090.     FRAME *np;
  2091.  
  2092.     fp->last->next = fp->next;
  2093.     fp->next->last = fp->last;
  2094.  
  2095.     if (showit) {
  2096.     werase(fp->wind);
  2097.     wrefresh(fp->wind);
  2098.     }
  2099.     delwin(fp->wind);
  2100.  
  2101.     np = (fp == fp->next) ? 0 : fp->next;
  2102.     free(fp);
  2103.     return np;
  2104. }
  2105.  
  2106. static void
  2107. acs_and_scroll(void)
  2108. /* Demonstrate windows */
  2109. {
  2110.     int c, i;
  2111.     FILE *fp;
  2112.     FRAME *current = (FRAME *) 0, *neww;
  2113.     WINDOW *usescr = stdscr;
  2114.  
  2115. #define DUMPFILE    "screendump"
  2116.  
  2117. #ifdef NCURSES_MOUSE_VERSION
  2118.     mousemask(BUTTON1_CLICKED, (mmask_t *) 0);
  2119. #endif
  2120.     c = CTRL('C');
  2121.     raw();
  2122.     do {
  2123.     transient((FRAME *) 0, (char *) 0);
  2124.     switch (c) {
  2125.     case CTRL('C'):
  2126.         neww = (FRAME *) calloc(1, sizeof(FRAME));
  2127.         if ((neww->wind = getwindow()) == (WINDOW *) 0)
  2128.         goto breakout;
  2129.  
  2130.         if (current == 0) {    /* First element,  */
  2131.         neww->next = neww;    /*   so point it at itself */
  2132.         neww->last = neww;
  2133.         } else {
  2134.         neww->next = current->next;
  2135.         neww->last = current;
  2136.         neww->last->next = neww;
  2137.         neww->next->last = neww;
  2138.         }
  2139.         current = neww;
  2140.         /* SVr4 curses sets the keypad on all newly-created windows to
  2141.          * false.  Someone reported that PDCurses makes new windows inherit
  2142.          * this flag.  Remove the following 'keypad()' call to test this
  2143.          */
  2144.         keypad(current->wind, TRUE);
  2145.         current->do_keypad = HaveKeypad(current);
  2146.         current->do_scroll = HaveScroll(current);
  2147.         break;
  2148.  
  2149.     case CTRL('N'):    /* go to next window */
  2150.         if (current)
  2151.         current = current->next;
  2152.         break;
  2153.  
  2154.     case CTRL('P'):    /* go to previous window */
  2155.         if (current)
  2156.         current = current->last;
  2157.         break;
  2158.  
  2159.     case CTRL('F'):    /* scroll current window forward */
  2160.         if (current)
  2161.         wscrl(current->wind, 1);
  2162.         break;
  2163.  
  2164.     case CTRL('B'):    /* scroll current window backwards */
  2165.         if (current)
  2166.         wscrl(current->wind, -1);
  2167.         break;
  2168.  
  2169.     case CTRL('K'):    /* toggle keypad mode for current */
  2170.         if (current) {
  2171.         current->do_keypad = !current->do_keypad;
  2172.         keypad(current->wind, current->do_keypad);
  2173.         }
  2174.         break;
  2175.  
  2176.     case CTRL('S'):
  2177.         if (current) {
  2178.         current->do_scroll = !current->do_scroll;
  2179.         scrollok(current->wind, current->do_scroll);
  2180.         }
  2181.         break;
  2182.  
  2183.     case CTRL('W'):    /* save and delete window */
  2184.         if (current == current->next) {
  2185.         transient(current, "Will not save/delete ONLY window");
  2186.         break;
  2187.         } else if ((fp = fopen(DUMPFILE, "w")) == (FILE *) 0) {
  2188.         transient(current, "Can't open screen dump file");
  2189.         } else {
  2190.         (void) putwin(current->wind, fp);
  2191.         (void) fclose(fp);
  2192.  
  2193.         current = delete_framed(current, TRUE);
  2194.         }
  2195.         break;
  2196.  
  2197.     case CTRL('R'):    /* restore window */
  2198.         if ((fp = fopen(DUMPFILE, "r")) == (FILE *) 0) {
  2199.         transient(current, "Can't open screen dump file");
  2200.         } else {
  2201.         neww = (FRAME *) calloc(1, sizeof(FRAME));
  2202.  
  2203.         neww->next = current->next;
  2204.         neww->last = current;
  2205.         neww->last->next = neww;
  2206.         neww->next->last = neww;
  2207.  
  2208.         neww->wind = getwin(fp);
  2209.         (void) fclose(fp);
  2210.  
  2211.         wrefresh(neww->wind);
  2212.         }
  2213.         break;
  2214.  
  2215. #if HAVE_WRESIZE
  2216.     case CTRL('X'):    /* resize window */
  2217.         if (current) {
  2218.         pair *tmp, ul, lr;
  2219.         int mx, my;
  2220.  
  2221.         move(0, 0);
  2222.         clrtoeol();
  2223.         addstr("Use arrows to move cursor, anything else to mark new corner");
  2224.         refresh();
  2225.  
  2226.         getbegyx(current->wind, ul.y, ul.x);
  2227.  
  2228.         tmp = selectcell(ul.y, ul.x, LINES - BOTLINES - 2, COLS - 2);
  2229.         if (tmp == (pair *) 0) {
  2230.             beep();
  2231.             break;
  2232.         }
  2233.  
  2234.         getmaxyx(current->wind, lr.y, lr.x);
  2235.         lr.y += (ul.y - 1);
  2236.         lr.x += (ul.x - 1);
  2237.         outerbox(ul, lr, FALSE);
  2238.         wnoutrefresh(stdscr);
  2239.  
  2240.         /* strictly cosmetic hack for the test */
  2241.         getmaxyx(current->wind, my, mx);
  2242.         if (my > tmp->y - ul.y) {
  2243.             getyx(current->wind, lr.y, lr.x);
  2244.             wmove(current->wind, tmp->y - ul.y + 1, 0);
  2245.             wclrtobot(current->wind);
  2246.             wmove(current->wind, lr.y, lr.x);
  2247.         }
  2248.         if (mx > tmp->x - ul.x)
  2249.             for (i = 0; i < my; i++) {
  2250.             wmove(current->wind, i, tmp->x - ul.x + 1);
  2251.             wclrtoeol(current->wind);
  2252.             }
  2253.         wnoutrefresh(current->wind);
  2254.  
  2255.         memcpy(&lr, tmp, sizeof(pair));
  2256.         (void) wresize(current->wind, lr.y - ul.y + 0, lr.x - ul.x + 0);
  2257.  
  2258.         getbegyx(current->wind, ul.y, ul.x);
  2259.         getmaxyx(current->wind, lr.y, lr.x);
  2260.         lr.y += (ul.y - 1);
  2261.         lr.x += (ul.x - 1);
  2262.         outerbox(ul, lr, TRUE);
  2263.         wnoutrefresh(stdscr);
  2264.  
  2265.         wnoutrefresh(current->wind);
  2266.         move(0, 0);
  2267.         clrtoeol();
  2268.         doupdate();
  2269.         }
  2270.         break;
  2271. #endif /* HAVE_WRESIZE */
  2272.  
  2273.     case KEY_F(10):    /* undocumented --- use this to test area clears */
  2274.         selectcell(0, 0, LINES - 1, COLS - 1);
  2275.         clrtobot();
  2276.         refresh();
  2277.         break;
  2278.  
  2279.     case KEY_UP:
  2280.         newwin_move(current, -1, 0);
  2281.         break;
  2282.     case KEY_DOWN:
  2283.         newwin_move(current, 1, 0);
  2284.         break;
  2285.     case KEY_LEFT:
  2286.         newwin_move(current, 0, -1);
  2287.         break;
  2288.     case KEY_RIGHT:
  2289.         newwin_move(current, 0, 1);
  2290.         break;
  2291.  
  2292.     case KEY_BACKSPACE:
  2293.         /* FALLTHROUGH */
  2294.     case KEY_DC:
  2295.         {
  2296.         int y, x;
  2297.         getyx(current->wind, y, x);
  2298.         if (--x < 0) {
  2299.             if (--y < 0)
  2300.             break;
  2301.             x = getmaxx(current->wind) - 1;
  2302.         }
  2303.         mvwdelch(current->wind, y, x);
  2304.         }
  2305.         break;
  2306.  
  2307.     case '\r':
  2308.         c = '\n';
  2309.         /* FALLTHROUGH */
  2310.  
  2311.     default:
  2312.         if (current)
  2313.         waddch(current->wind, (chtype) c);
  2314.         else
  2315.         beep();
  2316.         break;
  2317.     }
  2318.     newwin_report(current);
  2319.     usescr = (current ? current->wind : stdscr);
  2320.     wrefresh(usescr);
  2321.     } while
  2322.     ((c = wGetchar(usescr)) != QUIT
  2323.      && !((c == ESCAPE) && (keypad_active(usescr)))
  2324.      && (c != ERR));
  2325.  
  2326.   breakout:
  2327.     while (current != 0)
  2328.     current = delete_framed(current, FALSE);
  2329.  
  2330.     scrollok(stdscr, TRUE);    /* reset to driver's default */
  2331. #ifdef NCURSES_MOUSE_VERSION
  2332.     mousemask(0, (mmask_t *) 0);
  2333. #endif
  2334.     noraw();
  2335.     erase();
  2336.     endwin();
  2337. }
  2338.  
  2339. /****************************************************************************
  2340.  *
  2341.  * Panels tester
  2342.  *
  2343.  ****************************************************************************/
  2344.  
  2345. #if USE_LIBPANEL
  2346. static unsigned long nap_msec = 1;
  2347.  
  2348. static NCURSES_CONST char *mod[] =
  2349. {
  2350.     "test ",
  2351.     "TEST ",
  2352.     "(**) ",
  2353.     "*()* ",
  2354.     "<--> ",
  2355.     "LAST "
  2356. };
  2357.  
  2358. /*+-------------------------------------------------------------------------
  2359.     wait_a_while(msec)
  2360. --------------------------------------------------------------------------*/
  2361. static void
  2362. wait_a_while(unsigned long msec GCC_UNUSED)
  2363. {
  2364. #if HAVE_NAPMS
  2365.     if (nap_msec == 1)
  2366.     wGetchar(stdscr);
  2367.     else
  2368.     napms(nap_msec);
  2369. #else
  2370.     if (nap_msec == 1)
  2371.     wGetchar(stdscr);
  2372.     else if (msec > 1000L)
  2373.     sleep((int) msec / 1000L);
  2374.     else
  2375.     sleep(1);
  2376. #endif
  2377. }                /* end of wait_a_while */
  2378.  
  2379. /*+-------------------------------------------------------------------------
  2380.     saywhat(text)
  2381. --------------------------------------------------------------------------*/
  2382. static void
  2383. saywhat(NCURSES_CONST char *text)
  2384. {
  2385.     wmove(stdscr, LINES - 1, 0);
  2386.     wclrtoeol(stdscr);
  2387.     waddstr(stdscr, text);
  2388. }                /* end of saywhat */
  2389.  
  2390. /*+-------------------------------------------------------------------------
  2391.     mkpanel(rows,cols,tly,tlx) - alloc a win and panel and associate them
  2392. --------------------------------------------------------------------------*/
  2393. static PANEL *
  2394. mkpanel(int color, int rows, int cols, int tly, int tlx)
  2395. {
  2396.     WINDOW *win;
  2397.     PANEL *pan = 0;
  2398.  
  2399.     if ((win = newwin(rows, cols, tly, tlx)) != 0) {
  2400.     if ((pan = new_panel(win)) == 0) {
  2401.         delwin(win);
  2402.     } else if (has_colors()) {
  2403.         int fg = (color == COLOR_BLUE) ? COLOR_WHITE : COLOR_BLACK;
  2404.         int bg = color;
  2405.         init_pair(color, fg, bg);
  2406.         wbkgdset(win, COLOR_PAIR(color) | ' ');
  2407.     } else {
  2408.         wbkgdset(win, A_BOLD | ' ');
  2409.     }
  2410.     }
  2411.     return pan;
  2412. }                /* end of mkpanel */
  2413.  
  2414. /*+-------------------------------------------------------------------------
  2415.     rmpanel(pan)
  2416. --------------------------------------------------------------------------*/
  2417. static void
  2418. rmpanel(PANEL * pan)
  2419. {
  2420.     WINDOW *win = panel_window(pan);
  2421.     del_panel(pan);
  2422.     delwin(win);
  2423. }                /* end of rmpanel */
  2424.  
  2425. /*+-------------------------------------------------------------------------
  2426.     pflush()
  2427. --------------------------------------------------------------------------*/
  2428. static void
  2429. pflush(void)
  2430. {
  2431.     update_panels();
  2432.     doupdate();
  2433. }                /* end of pflush */
  2434.  
  2435. /*+-------------------------------------------------------------------------
  2436.     fill_panel(win)
  2437. --------------------------------------------------------------------------*/
  2438. static void
  2439. fill_panel(PANEL * pan)
  2440. {
  2441.     WINDOW *win = panel_window(pan);
  2442.     int num = ((const char *) panel_userptr(pan))[1];
  2443.     int y, x;
  2444.  
  2445.     wmove(win, 1, 1);
  2446.     wprintw(win, "-pan%c-", num);
  2447.     wclrtoeol(win);
  2448.     box(win, 0, 0);
  2449.     for (y = 2; y < getmaxy(win) - 1; y++) {
  2450.     for (x = 1; x < getmaxx(win) - 1; x++) {
  2451.         wmove(win, y, x);
  2452.         waddch(win, num);
  2453.     }
  2454.     }
  2455. }                /* end of fill_panel */
  2456.  
  2457. static void
  2458. demo_panels(void)
  2459. {
  2460.     int itmp;
  2461.     register int y, x;
  2462.  
  2463.     refresh();
  2464.  
  2465.     for (y = 0; y < LINES - 1; y++) {
  2466.     for (x = 0; x < COLS; x++)
  2467.         wprintw(stdscr, "%d", (y + x) % 10);
  2468.     }
  2469.     for (y = 0; y < 5; y++) {
  2470.     PANEL *p1;
  2471.     PANEL *p2;
  2472.     PANEL *p3;
  2473.     PANEL *p4;
  2474.     PANEL *p5;
  2475.  
  2476.     p1 = mkpanel(COLOR_RED,
  2477.              LINES / 2 - 2,
  2478.              COLS / 8 + 1,
  2479.              0,
  2480.              0);
  2481.     set_panel_userptr(p1, "p1");
  2482.  
  2483.     p2 = mkpanel(COLOR_GREEN,
  2484.              LINES / 2 + 1,
  2485.              COLS / 7,
  2486.              LINES / 4,
  2487.              COLS / 10);
  2488.     set_panel_userptr(p2, "p2");
  2489.  
  2490.     p3 = mkpanel(COLOR_YELLOW,
  2491.              LINES / 4,
  2492.              COLS / 10,
  2493.              LINES / 2,
  2494.              COLS / 9);
  2495.     set_panel_userptr(p3, "p3");
  2496.  
  2497.     p4 = mkpanel(COLOR_BLUE,
  2498.              LINES / 2 - 2,
  2499.              COLS / 8,
  2500.              LINES / 2 - 2,
  2501.              COLS / 3);
  2502.     set_panel_userptr(p4, "p4");
  2503.  
  2504.     p5 = mkpanel(COLOR_MAGENTA,
  2505.              LINES / 2 - 2,
  2506.              COLS / 8,
  2507.              LINES / 2,
  2508.              COLS / 2 - 2);
  2509.     set_panel_userptr(p5, "p5");
  2510.  
  2511.     fill_panel(p1);
  2512.     fill_panel(p2);
  2513.     fill_panel(p3);
  2514.     fill_panel(p4);
  2515.     fill_panel(p5);
  2516.     hide_panel(p4);
  2517.     hide_panel(p5);
  2518.     pflush();
  2519.     saywhat("press any key to continue");
  2520.     wait_a_while(nap_msec);
  2521.  
  2522.     saywhat("h3 s1 s2 s4 s5; press any key to continue");
  2523.     move_panel(p1, 0, 0);
  2524.     hide_panel(p3);
  2525.     show_panel(p1);
  2526.     show_panel(p2);
  2527.     show_panel(p4);
  2528.     show_panel(p5);
  2529.     pflush();
  2530.     wait_a_while(nap_msec);
  2531.  
  2532.     saywhat("s1; press any key to continue");
  2533.     show_panel(p1);
  2534.     pflush();
  2535.     wait_a_while(nap_msec);
  2536.  
  2537.     saywhat("s2; press any key to continue");
  2538.     show_panel(p2);
  2539.     pflush();
  2540.     wait_a_while(nap_msec);
  2541.  
  2542.     saywhat("m2; press any key to continue");
  2543.     move_panel(p2, LINES / 3 + 1, COLS / 8);
  2544.     pflush();
  2545.     wait_a_while(nap_msec);
  2546.  
  2547.     saywhat("s3;");
  2548.     show_panel(p3);
  2549.     pflush();
  2550.     wait_a_while(nap_msec);
  2551.  
  2552.     saywhat("m3; press any key to continue");
  2553.     move_panel(p3, LINES / 4 + 1, COLS / 15);
  2554.     pflush();
  2555.     wait_a_while(nap_msec);
  2556.  
  2557.     saywhat("b3; press any key to continue");
  2558.     bottom_panel(p3);
  2559.     pflush();
  2560.     wait_a_while(nap_msec);
  2561.  
  2562.     saywhat("s4; press any key to continue");
  2563.     show_panel(p4);
  2564.     pflush();
  2565.     wait_a_while(nap_msec);
  2566.  
  2567.     saywhat("s5; press any key to continue");
  2568.     show_panel(p5);
  2569.     pflush();
  2570.     wait_a_while(nap_msec);
  2571.  
  2572.     saywhat("t3; press any key to continue");
  2573.     top_panel(p3);
  2574.     pflush();
  2575.     wait_a_while(nap_msec);
  2576.  
  2577.     saywhat("t1; press any key to continue");
  2578.     top_panel(p1);
  2579.     pflush();
  2580.     wait_a_while(nap_msec);
  2581.  
  2582.     saywhat("t2; press any key to continue");
  2583.     top_panel(p2);
  2584.     pflush();
  2585.     wait_a_while(nap_msec);
  2586.  
  2587.     saywhat("t3; press any key to continue");
  2588.     top_panel(p3);
  2589.     pflush();
  2590.     wait_a_while(nap_msec);
  2591.  
  2592.     saywhat("t4; press any key to continue");
  2593.     top_panel(p4);
  2594.     pflush();
  2595.     wait_a_while(nap_msec);
  2596.  
  2597.     for (itmp = 0; itmp < 6; itmp++) {
  2598.         WINDOW *w4 = panel_window(p4);
  2599.         WINDOW *w5 = panel_window(p5);
  2600.  
  2601.         saywhat("m4; press any key to continue");
  2602.         wmove(w4, LINES / 8, 1);
  2603.         waddstr(w4, mod[itmp]);
  2604.         move_panel(p4, LINES / 6, itmp * (COLS / 8));
  2605.         wmove(w5, LINES / 6, 1);
  2606.         waddstr(w5, mod[itmp]);
  2607.         pflush();
  2608.         wait_a_while(nap_msec);
  2609.  
  2610.         saywhat("m5; press any key to continue");
  2611.         wmove(w4, LINES / 6, 1);
  2612.         waddstr(w4, mod[itmp]);
  2613.         move_panel(p5, LINES / 3 - 1, (itmp * 10) + 6);
  2614.         wmove(w5, LINES / 8, 1);
  2615.         waddstr(w5, mod[itmp]);
  2616.         pflush();
  2617.         wait_a_while(nap_msec);
  2618.     }
  2619.  
  2620.     saywhat("m4; press any key to continue");
  2621.     move_panel(p4, LINES / 6, itmp * (COLS / 8));
  2622.     pflush();
  2623.     wait_a_while(nap_msec);
  2624.  
  2625.     saywhat("t5; press any key to continue");
  2626.     top_panel(p5);
  2627.     pflush();
  2628.     wait_a_while(nap_msec);
  2629.  
  2630.     saywhat("t2; press any key to continue");
  2631.     top_panel(p2);
  2632.     pflush();
  2633.     wait_a_while(nap_msec);
  2634.  
  2635.     saywhat("t1; press any key to continue");
  2636.     top_panel(p1);
  2637.     pflush();
  2638.     wait_a_while(nap_msec);
  2639.  
  2640.     saywhat("d2; press any key to continue");
  2641.     rmpanel(p2);
  2642.     pflush();
  2643.     wait_a_while(nap_msec);
  2644.  
  2645.     saywhat("h3; press any key to continue");
  2646.     hide_panel(p3);
  2647.     pflush();
  2648.     wait_a_while(nap_msec);
  2649.  
  2650.     saywhat("d1; press any key to continue");
  2651.     rmpanel(p1);
  2652.     pflush();
  2653.     wait_a_while(nap_msec);
  2654.  
  2655.     saywhat("d4; press any key to continue");
  2656.     rmpanel(p4);
  2657.     pflush();
  2658.     wait_a_while(nap_msec);
  2659.  
  2660.     saywhat("d5; press any key to continue");
  2661.     rmpanel(p5);
  2662.     pflush();
  2663.     wait_a_while(nap_msec);
  2664.     if (nap_msec == 1)
  2665.         break;
  2666.     nap_msec = 100L;
  2667.     }
  2668.  
  2669.     erase();
  2670.     endwin();
  2671. }
  2672.  
  2673. /****************************************************************************
  2674.  *
  2675.  * Pad tester
  2676.  *
  2677.  ****************************************************************************/
  2678.  
  2679. #define GRIDSIZE    3
  2680.  
  2681. static bool pending_pan = FALSE;
  2682. static bool show_panner_legend = TRUE;
  2683.  
  2684. static int
  2685. panner_legend(int line)
  2686. {
  2687.     static const char *const legend[] =
  2688.     {
  2689.     "Use arrow keys (or U,D,L,R) to pan, q to quit, ! to shell-out.",
  2690.     "Use +,- (or j,k) to grow/shrink the panner vertically.",
  2691.     "Use <,> (or h,l) to grow/shrink the panner horizontally.",
  2692.     "Number repeats.  Toggle legend:?, timer:t, scroll mark:s."
  2693.     };
  2694.     int n = (SIZEOF(legend) - (LINES - line));
  2695.     if (line < LINES && (n >= 0)) {
  2696.     move(line, 0);
  2697.     if (show_panner_legend)
  2698.         printw("%s", legend[n]);
  2699.     clrtoeol();
  2700.     return show_panner_legend;
  2701.     }
  2702.     return FALSE;
  2703. }
  2704.  
  2705. static void
  2706. panner_h_cleanup(int from_y, int from_x, int to_x)
  2707. {
  2708.     if (!panner_legend(from_y))
  2709.     do_h_line(from_y, from_x, ' ', to_x);
  2710. }
  2711.  
  2712. static void
  2713. panner_v_cleanup(int from_y, int from_x, int to_y)
  2714. {
  2715.     if (!panner_legend(from_y))
  2716.     do_v_line(from_y, from_x, ' ', to_y);
  2717. }
  2718.  
  2719. static void
  2720. panner(WINDOW *pad,
  2721.        int top_x, int top_y, int porty, int portx,
  2722.        int (*pgetc) (WINDOW *))
  2723. {
  2724. #if HAVE_GETTIMEOFDAY
  2725.     struct timeval before, after;
  2726.     bool timing = TRUE;
  2727. #endif
  2728.     bool scrollers = TRUE;
  2729.     int basex = 0;
  2730.     int basey = 0;
  2731.     int pxmax, pymax, lowend, highend, c;
  2732.  
  2733.     getmaxyx(pad, pymax, pxmax);
  2734.     scrollok(stdscr, FALSE);    /* we don't want stdscr to scroll! */
  2735.  
  2736.     c = KEY_REFRESH;
  2737.     do {
  2738. #ifdef NCURSES_VERSION
  2739.     /*
  2740.      * During shell-out, the user may have resized the window.  Adjust
  2741.      * the port size of the pad to accommodate this.  Ncurses automatically
  2742.      * resizes all of the normal windows to fit on the new screen.
  2743.      */
  2744.     if (top_x > COLS)
  2745.         top_x = COLS;
  2746.     if (portx > COLS)
  2747.         portx = COLS;
  2748.     if (top_y > LINES)
  2749.         top_y = LINES;
  2750.     if (porty > LINES)
  2751.         porty = LINES;
  2752. #endif
  2753.     switch (c) {
  2754.     case KEY_REFRESH:
  2755.         erase();
  2756.  
  2757.         /* FALLTHRU */
  2758.     case '?':
  2759.         if (c == '?')
  2760.         show_panner_legend = !show_panner_legend;
  2761.         panner_legend(LINES - 4);
  2762.         panner_legend(LINES - 3);
  2763.         panner_legend(LINES - 2);
  2764.         panner_legend(LINES - 1);
  2765.         break;
  2766. #if HAVE_GETTIMEOFDAY
  2767.     case 't':
  2768.         timing = !timing;
  2769.         if (!timing)
  2770.         panner_legend(LINES - 1);
  2771.         break;
  2772. #endif
  2773.     case 's':
  2774.         scrollers = !scrollers;
  2775.         break;
  2776.  
  2777.         /* Move the top-left corner of the pad, keeping the bottom-right
  2778.          * corner fixed.
  2779.          */
  2780.     case 'h':        /* increase-columns: move left edge to left */
  2781.         if (top_x <= 0)
  2782.         beep();
  2783.         else {
  2784.         panner_v_cleanup(top_y, top_x, porty);
  2785.         top_x--;
  2786.         }
  2787.         break;
  2788.  
  2789.     case 'j':        /* decrease-lines: move top-edge down */
  2790.         if (top_y >= porty)
  2791.         beep();
  2792.         else {
  2793.         panner_h_cleanup(top_y - 1, top_x - (top_x > 0), portx);
  2794.         top_y++;
  2795.         }
  2796.         break;
  2797.  
  2798.     case 'k':        /* increase-lines: move top-edge up */
  2799.         if (top_y <= 0)
  2800.         beep();
  2801.         else {
  2802.         top_y--;
  2803.         panner_h_cleanup(top_y, top_x, portx);
  2804.         }
  2805.         break;
  2806.  
  2807.     case 'l':        /* decrease-columns: move left-edge to right */
  2808.         if (top_x >= portx)
  2809.         beep();
  2810.         else {
  2811.         panner_v_cleanup(top_y - (top_y > 0), top_x - 1, porty);
  2812.         top_x++;
  2813.         }
  2814.         break;
  2815.  
  2816.         /* Move the bottom-right corner of the pad, keeping the top-left
  2817.          * corner fixed.
  2818.          */
  2819.     case KEY_IC:        /* increase-columns: move right-edge to right */
  2820.         if (portx >= pxmax || portx >= COLS)
  2821.         beep();
  2822.         else {
  2823.         panner_v_cleanup(top_y - (top_y > 0), portx - 1, porty);
  2824.         ++portx;
  2825.         }
  2826.         break;
  2827.  
  2828.     case KEY_IL:        /* increase-lines: move bottom-edge down */
  2829.         if (porty >= pymax || porty >= LINES)
  2830.         beep();
  2831.         else {
  2832.         panner_h_cleanup(porty - 1, top_x - (top_x > 0), portx);
  2833.         ++porty;
  2834.         }
  2835.         break;
  2836.  
  2837.     case KEY_DC:        /* decrease-columns: move bottom edge up */
  2838.         if (portx <= top_x)
  2839.         beep();
  2840.         else {
  2841.         portx--;
  2842.         panner_v_cleanup(top_y - (top_y > 0), portx, porty);
  2843.         }
  2844.         break;
  2845.  
  2846.     case KEY_DL:        /* decrease-lines */
  2847.         if (porty <= top_y)
  2848.         beep();
  2849.         else {
  2850.         porty--;
  2851.         panner_h_cleanup(porty, top_x - (top_x > 0), portx);
  2852.         }
  2853.         break;
  2854.  
  2855.     case KEY_LEFT:        /* pan leftwards */
  2856.         if (basex > 0)
  2857.         basex--;
  2858.         else
  2859.         beep();
  2860.         break;
  2861.  
  2862.     case KEY_RIGHT:    /* pan rightwards */
  2863.         if (basex + portx - (pymax > porty) < pxmax)
  2864.         basex++;
  2865.         else
  2866.         beep();
  2867.         break;
  2868.  
  2869.     case KEY_UP:        /* pan upwards */
  2870.         if (basey > 0)
  2871.         basey--;
  2872.         else
  2873.         beep();
  2874.         break;
  2875.  
  2876.     case KEY_DOWN:        /* pan downwards */
  2877.         if (basey + porty - (pxmax > portx) < pymax)
  2878.         basey++;
  2879.         else
  2880.         beep();
  2881.         break;
  2882.  
  2883.     case 'H':
  2884.     case KEY_HOME:
  2885.     case KEY_FIND:
  2886.         basey = 0;
  2887.         break;
  2888.  
  2889.     case 'E':
  2890.     case KEY_END:
  2891.     case KEY_SELECT:
  2892.         basey = pymax - porty;
  2893.         if (basey < 0)
  2894.         basey = 0;
  2895.         break;
  2896.  
  2897.     default:
  2898.         beep();
  2899.         break;
  2900.     }
  2901.  
  2902.     mvaddch(top_y - 1, top_x - 1, ACS_ULCORNER);
  2903.     do_v_line(top_y, top_x - 1, ACS_VLINE, porty);
  2904.     do_h_line(top_y - 1, top_x, ACS_HLINE, portx);
  2905.  
  2906.     if (scrollers && (pxmax > portx - 1)) {
  2907.         int length = (portx - top_x - 1);
  2908.         float ratio = ((float) length) / ((float) pxmax);
  2909.  
  2910.         lowend = (int) (top_x + (basex * ratio));
  2911.         highend = (int) (top_x + ((basex + length) * ratio));
  2912.  
  2913.         do_h_line(porty - 1, top_x, ACS_HLINE, lowend);
  2914.         if (highend < portx) {
  2915.         attron(A_REVERSE);
  2916.         do_h_line(porty - 1, lowend, ' ', highend + 1);
  2917.         attroff(A_REVERSE);
  2918.         do_h_line(porty - 1, highend + 1, ACS_HLINE, portx);
  2919.         }
  2920.     } else
  2921.         do_h_line(porty - 1, top_x, ACS_HLINE, portx);
  2922.  
  2923.     if (scrollers && (pymax > porty - 1)) {
  2924.         int length = (porty - top_y - 1);
  2925.         float ratio = ((float) length) / ((float) pymax);
  2926.  
  2927.         lowend = (int) (top_y + (basey * ratio));
  2928.         highend = (int) (top_y + ((basey + length) * ratio));
  2929.  
  2930.         do_v_line(top_y, portx - 1, ACS_VLINE, lowend);
  2931.         if (highend < porty) {
  2932.         attron(A_REVERSE);
  2933.         do_v_line(lowend, portx - 1, ' ', highend + 1);
  2934.         attroff(A_REVERSE);
  2935.         do_v_line(highend + 1, portx - 1, ACS_VLINE, porty);
  2936.         }
  2937.     } else
  2938.         do_v_line(top_y, portx - 1, ACS_VLINE, porty);
  2939.  
  2940.     mvaddch(top_y - 1, portx - 1, ACS_URCORNER);
  2941.     mvaddch(porty - 1, top_x - 1, ACS_LLCORNER);
  2942.     mvaddch(porty - 1, portx - 1, ACS_LRCORNER);
  2943.  
  2944.     if (!pending_pan) {
  2945. #if HAVE_GETTIMEOFDAY
  2946.         gettimeofday(&before, 0);
  2947. #endif
  2948.         wnoutrefresh(stdscr);
  2949.  
  2950.         pnoutrefresh(pad,
  2951.              basey, basex,
  2952.              top_y, top_x,
  2953.              porty - (pxmax > portx) - 1,
  2954.              portx - (pymax > porty) - 1);
  2955.  
  2956.         doupdate();
  2957. #if HAVE_GETTIMEOFDAY
  2958.         if (timing) {
  2959.         double elapsed;
  2960.         gettimeofday(&after, 0);
  2961.         elapsed = (after.tv_sec + after.tv_usec / 1.0e6)
  2962.             - (before.tv_sec + before.tv_usec / 1.0e6);
  2963.         move(LINES - 1, COLS - 20);
  2964.         printw("Secs: %2.03f", elapsed);
  2965.         refresh();
  2966.         }
  2967. #endif
  2968.     }
  2969.  
  2970.     } while
  2971.     ((c = pgetc(pad)) != KEY_EXIT);
  2972.  
  2973.     scrollok(stdscr, TRUE);    /* reset to driver's default */
  2974. }
  2975.  
  2976. static int
  2977. padgetch(WINDOW *win)
  2978. {
  2979.     static int count;
  2980.     static int last;
  2981.     int c;
  2982.  
  2983.     if ((pending_pan = (count > 0)) != FALSE) {
  2984.     count--;
  2985.     pending_pan = (count != 0);
  2986.     } else {
  2987.     for (;;) {
  2988.         switch (c = wGetchar(win)) {
  2989.         case '!':
  2990.         ShellOut(FALSE);
  2991.         /* FALLTHRU */
  2992.         case CTRL('r'):
  2993.         endwin();
  2994.         refresh();
  2995.         c = KEY_REFRESH;
  2996.         break;
  2997.         case CTRL('l'):
  2998.         c = KEY_REFRESH;
  2999.         break;
  3000.         case 'U':
  3001.         c = KEY_UP;
  3002.         break;
  3003.         case 'D':
  3004.         c = KEY_DOWN;
  3005.         break;
  3006.         case 'R':
  3007.         c = KEY_RIGHT;
  3008.         break;
  3009.         case 'L':
  3010.         c = KEY_LEFT;
  3011.         break;
  3012.         case '+':
  3013.         c = KEY_IL;
  3014.         break;
  3015.         case '-':
  3016.         c = KEY_DL;
  3017.         break;
  3018.         case '>':
  3019.         c = KEY_IC;
  3020.         break;
  3021.         case '<':
  3022.         c = KEY_DC;
  3023.         break;
  3024.         case ERR:        /* FALLTHRU */
  3025.         case 'q':
  3026.         count = 0;
  3027.         c = KEY_EXIT;
  3028.         break;
  3029.         default:
  3030.         if (c >= '0' && c <= '9') {
  3031.             count = count * 10 + (c - '0');
  3032.             continue;
  3033.         }
  3034.         break;
  3035.         }
  3036.         last = c;
  3037.         break;
  3038.     }
  3039.     if (count > 0)
  3040.         count--;
  3041.     }
  3042.     return (last);
  3043. }
  3044.  
  3045. #define PAD_HIGH 200
  3046. #define PAD_WIDE 200
  3047.  
  3048. static void
  3049. demo_pad(void)
  3050. /* Demonstrate pads. */
  3051. {
  3052.     int i, j;
  3053.     unsigned gridcount = 0;
  3054.     WINDOW *panpad = newpad(PAD_HIGH, PAD_WIDE);
  3055.  
  3056.     if (panpad == 0) {
  3057.     Cannot("cannot create requested pad");
  3058.     return;
  3059.     }
  3060.  
  3061.     for (i = 0; i < PAD_HIGH; i++) {
  3062.     for (j = 0; j < PAD_WIDE; j++)
  3063.         if (i % GRIDSIZE == 0 && j % GRIDSIZE == 0) {
  3064.         if (i == 0 || j == 0)
  3065.             waddch(panpad, '+');
  3066.         else
  3067.             waddch(panpad, (chtype) ('A' + (gridcount++ % 26)));
  3068.         } else if (i % GRIDSIZE == 0)
  3069.         waddch(panpad, '-');
  3070.         else if (j % GRIDSIZE == 0)
  3071.         waddch(panpad, '|');
  3072.         else
  3073.         waddch(panpad, ' ');
  3074.     }
  3075.     panner_legend(LINES - 4);
  3076.     panner_legend(LINES - 3);
  3077.     panner_legend(LINES - 2);
  3078.     panner_legend(LINES - 1);
  3079.  
  3080.     keypad(panpad, TRUE);
  3081.  
  3082.     /* Make the pad (initially) narrow enough that a trace file won't wrap.
  3083.      * We'll still be able to widen it during a test, since that's required
  3084.      * for testing boundaries.
  3085.      */
  3086.     panner(panpad, 2, 2, LINES - 5, COLS - 15, padgetch);
  3087.  
  3088.     delwin(panpad);
  3089.     endwin();
  3090.     erase();
  3091. }
  3092. #endif /* USE_LIBPANEL */
  3093.  
  3094. /****************************************************************************
  3095.  *
  3096.  * Tests from John Burnell's PDCurses tester
  3097.  *
  3098.  ****************************************************************************/
  3099.  
  3100. static void
  3101. Continue(WINDOW *win)
  3102. {
  3103.     noecho();
  3104.     wmove(win, 10, 1);
  3105.     mvwaddstr(win, 10, 1, " Press any key to continue");
  3106.     wrefresh(win);
  3107.     wGetchar(win);
  3108. }
  3109.  
  3110. static void
  3111. flushinp_test(WINDOW *win)
  3112. /* Input test, adapted from John Burnell's PDCurses tester */
  3113. {
  3114.     int w, h, bx, by, sw, sh, i;
  3115.  
  3116.     WINDOW *subWin;
  3117.     wclear(win);
  3118.  
  3119.     getmaxyx(win, h, w);
  3120.     getbegyx(win, by, bx);
  3121.     sw = w / 3;
  3122.     sh = h / 3;
  3123.     if ((subWin = subwin(win, sh, sw, by + h - sh - 2, bx + w - sw - 2)) == 0)
  3124.     return;
  3125.  
  3126. #ifdef A_COLOR
  3127.     if (has_colors()) {
  3128.     init_pair(2, COLOR_CYAN, COLOR_BLUE);
  3129.     wbkgd(subWin, COLOR_PAIR(2) | ' ');
  3130.     }
  3131. #endif
  3132.     wattrset(subWin, A_BOLD);
  3133.     box(subWin, ACS_VLINE, ACS_HLINE);
  3134.     mvwaddstr(subWin, 2, 1, "This is a subwindow");
  3135.     wrefresh(win);
  3136.  
  3137.     /*
  3138.      * This used to set 'nocbreak()'.  However, Alexander Lukyanov says that
  3139.      * it only happened to "work" on SVr4 because that implementation does not
  3140.      * emulate nocbreak+noecho mode, whereas ncurses does.  To get the desired
  3141.      * test behavior, we're using 'cbreak()', which will allow a single
  3142.      * character to return without needing a newline. - T.Dickey 1997/10/11.
  3143.      */
  3144.     cbreak();
  3145.     mvwaddstr(win, 0, 1, "This is a test of the flushinp() call.");
  3146.  
  3147.     mvwaddstr(win, 2, 1, "Type random keys for 5 seconds.");
  3148.     mvwaddstr(win, 3, 1,
  3149.           "These should be discarded (not echoed) after the subwindow goes away.");
  3150.     wrefresh(win);
  3151.  
  3152.     for (i = 0; i < 5; i++) {
  3153.     mvwprintw(subWin, 1, 1, "Time = %d", i);
  3154.     wrefresh(subWin);
  3155.     napms(1000);
  3156.     flushinp();
  3157.     }
  3158.  
  3159.     delwin(subWin);
  3160.     werase(win);
  3161.     flash();
  3162.     wrefresh(win);
  3163.     napms(1000);
  3164.  
  3165.     mvwaddstr(win, 2, 1,
  3166.           "If you were still typing when the window timer expired,");
  3167.     mvwaddstr(win, 3, 1,
  3168.           "or else you typed nothing at all while it was running,");
  3169.     mvwaddstr(win, 4, 1,
  3170.           "test was invalid.  You'll see garbage or nothing at all. ");
  3171.     mvwaddstr(win, 6, 1, "Press a key");
  3172.     wmove(win, 9, 10);
  3173.     wrefresh(win);
  3174.     echo();
  3175.     wGetchar(win);
  3176.     flushinp();
  3177.     mvwaddstr(win, 12, 0,
  3178.           "If you see any key other than what you typed, flushinp() is broken.");
  3179.     Continue(win);
  3180.  
  3181.     wmove(win, 9, 10);
  3182.     wdelch(win);
  3183.     wrefresh(win);
  3184.     wmove(win, 12, 0);
  3185.     clrtoeol();
  3186.     waddstr(win,
  3187.         "What you typed should now have been deleted; if not, wdelch() failed.");
  3188.     Continue(win);
  3189.  
  3190.     cbreak();
  3191. }
  3192.  
  3193. /****************************************************************************
  3194.  *
  3195.  * Menu test
  3196.  *
  3197.  ****************************************************************************/
  3198.  
  3199. #if USE_LIBMENU
  3200.  
  3201. #define MENU_Y    8
  3202. #define MENU_X    8
  3203.  
  3204. static int
  3205. menu_virtualize(int c)
  3206. {
  3207.     if (c == '\n' || c == KEY_EXIT)
  3208.     return (MAX_COMMAND + 1);
  3209.     else if (c == 'u')
  3210.     return (REQ_SCR_ULINE);
  3211.     else if (c == 'd')
  3212.     return (REQ_SCR_DLINE);
  3213.     else if (c == 'b' || c == KEY_NPAGE)
  3214.     return (REQ_SCR_UPAGE);
  3215.     else if (c == 'f' || c == KEY_PPAGE)
  3216.     return (REQ_SCR_DPAGE);
  3217.     else if (c == 'n' || c == KEY_DOWN)
  3218.     return (REQ_NEXT_ITEM);
  3219.     else if (c == 'p' || c == KEY_UP)
  3220.     return (REQ_PREV_ITEM);
  3221.     else if (c == ' ')
  3222.     return (REQ_TOGGLE_ITEM);
  3223.     else {
  3224.     if (c != KEY_MOUSE)
  3225.         beep();
  3226.     return (c);
  3227.     }
  3228. }
  3229.  
  3230. static const char *animals[] =
  3231. {
  3232.     "Lions", "Tigers", "Bears", "(Oh my!)", "Newts", "Platypi", "Lemurs",
  3233.     (char *) 0
  3234. };
  3235.  
  3236. static void
  3237. menu_test(void)
  3238. {
  3239.     MENU *m;
  3240.     ITEM *items[SIZEOF(animals)];
  3241.     ITEM **ip = items;
  3242.     const char **ap;
  3243.     int mrows, mcols, c;
  3244.     WINDOW *menuwin;
  3245.  
  3246. #ifdef NCURSES_MOUSE_VERSION
  3247.     mousemask(ALL_MOUSE_EVENTS, (mmask_t *) 0);
  3248. #endif
  3249.     mvaddstr(0, 0, "This is the menu test:");
  3250.     mvaddstr(2, 0, "  Use up and down arrow to move the select bar.");
  3251.     mvaddstr(3, 0, "  'n' and 'p' act like arrows.");
  3252.     mvaddstr(4, 0,
  3253.          "  'b' and 'f' scroll up/down (page), 'u' and 'd' (line).");
  3254.     mvaddstr(5, 0, "  Press return to exit.");
  3255.     refresh();
  3256.  
  3257.     for (ap = animals; *ap; ap++)
  3258.     *ip++ = new_item(*ap, "");
  3259.     *ip = (ITEM *) 0;
  3260.  
  3261.     m = new_menu(items);
  3262.  
  3263.     set_menu_format(m, (SIZEOF(animals) + 1) / 2, 1);
  3264.     scale_menu(m, &mrows, &mcols);
  3265.  
  3266.     menuwin = newwin(mrows + 2, mcols + 2, MENU_Y, MENU_X);
  3267.     set_menu_win(m, menuwin);
  3268.     keypad(menuwin, TRUE);
  3269.     box(menuwin, 0, 0);
  3270.  
  3271.     set_menu_sub(m, derwin(menuwin, mrows, mcols, 1, 1));
  3272.  
  3273.     post_menu(m);
  3274.  
  3275.     while ((c = menu_driver(m, menu_virtualize(wGetchar(menuwin)))) != E_UNKNOWN_COMMAND) {
  3276.     if (c == E_REQUEST_DENIED)
  3277.         beep();
  3278.     continue;
  3279.     }
  3280.  
  3281.     (void) mvprintw(LINES - 2, 0,
  3282.             "You chose: %s\n", item_name(current_item(m)));
  3283.     (void) addstr("Press any key to continue...");
  3284.     wGetchar(stdscr);
  3285.  
  3286.     unpost_menu(m);
  3287.     delwin(menuwin);
  3288.  
  3289.     free_menu(m);
  3290.     for (ip = items; *ip; ip++)
  3291.     free_item(*ip);
  3292. #ifdef NCURSES_MOUSE_VERSION
  3293.     mousemask(0, (mmask_t *) 0);
  3294. #endif
  3295. }
  3296.  
  3297. #ifdef TRACE
  3298. #define T_TBL(name) { #name, name }
  3299. static struct {
  3300.     const char *name;
  3301.     int mask;
  3302. } t_tbl[] = {
  3303.  
  3304.     T_TBL(TRACE_DISABLE),
  3305.     T_TBL(TRACE_TIMES),
  3306.     T_TBL(TRACE_TPUTS),
  3307.     T_TBL(TRACE_UPDATE),
  3308.     T_TBL(TRACE_MOVE),
  3309.     T_TBL(TRACE_CHARPUT),
  3310.     T_TBL(TRACE_ORDINARY),
  3311.     T_TBL(TRACE_CALLS),
  3312.     T_TBL(TRACE_VIRTPUT),
  3313.     T_TBL(TRACE_IEVENT),
  3314.     T_TBL(TRACE_BITS),
  3315.     T_TBL(TRACE_ICALLS),
  3316.     T_TBL(TRACE_CCALLS),
  3317.     T_TBL(TRACE_DATABASE),
  3318.     T_TBL(TRACE_ATTRS),
  3319.     T_TBL(TRACE_MAXIMUM),
  3320.     {
  3321.     (char *) 0, 0
  3322.     }
  3323. };
  3324.  
  3325. static char *
  3326. tracetrace(int tlevel)
  3327. {
  3328.     static char *buf;
  3329.     int n;
  3330.  
  3331.     if (buf == 0) {
  3332.     size_t need = 12;
  3333.     for (n = 0; t_tbl[n].name != 0; n++)
  3334.         need += strlen(t_tbl[n].name) + 2;
  3335.     buf = (char *) malloc(need);
  3336.     }
  3337.     sprintf(buf, "0x%02x = {", tlevel);
  3338.     if (tlevel == 0) {
  3339.     sprintf(buf + strlen(buf), "%s, ", t_tbl[0].name);
  3340.     } else {
  3341.     for (n = 1; t_tbl[n].name != 0; n++)
  3342.         if ((tlevel & t_tbl[n].mask) == t_tbl[n].mask) {
  3343.         strcat(buf, t_tbl[n].name);
  3344.         strcat(buf, ", ");
  3345.         }
  3346.     }
  3347.     if (buf[strlen(buf) - 2] == ',')
  3348.     buf[strlen(buf) - 2] = '\0';
  3349.     return (strcat(buf, "}"));
  3350. }
  3351.  
  3352. /* fake a dynamically reconfigurable menu using the 0th entry to deselect
  3353.  * the others
  3354.  */
  3355. static int
  3356. run_trace_menu(MENU * m)
  3357. {
  3358.     ITEM **items;
  3359.     ITEM *i, **p;
  3360.  
  3361.     for (;;) {
  3362.     bool changed = FALSE;
  3363.     switch (menu_driver(m, menu_virtualize(wGetchar(menu_win(m))))) {
  3364.     case E_UNKNOWN_COMMAND:
  3365.         return FALSE;
  3366.     default:
  3367.         items = menu_items(m);
  3368.         i = current_item(m);
  3369.         if (i == items[0]) {
  3370.         if (item_value(i)) {
  3371.             for (p = items + 1; *p != 0; p++)
  3372.             if (item_value(*p)) {
  3373.                 set_item_value(*p, FALSE);
  3374.                 changed = TRUE;
  3375.             }
  3376.         }
  3377.         } else {
  3378.         for (p = items + 1; *p != 0; p++)
  3379.             if (item_value(*p)) {
  3380.             set_item_value(items[0], FALSE);
  3381.             changed = TRUE;
  3382.             break;
  3383.             }
  3384.         }
  3385.         if (!changed)
  3386.         return TRUE;
  3387.     }
  3388.     }
  3389. }
  3390.  
  3391. static void
  3392. trace_set(void)
  3393. /* interactively set the trace level */
  3394. {
  3395.     MENU *m;
  3396.     ITEM *items[SIZEOF(t_tbl)];
  3397.     ITEM **ip = items;
  3398.     int mrows, mcols, newtrace;
  3399.     int n;
  3400.     WINDOW *menuwin;
  3401.  
  3402.     mvaddstr(0, 0, "Interactively set trace level:");
  3403.     mvaddstr(2, 0, "  Press space bar to toggle a selection.");
  3404.     mvaddstr(3, 0, "  Use up and down arrow to move the select bar.");
  3405.     mvaddstr(4, 0, "  Press return to set the trace level.");
  3406.     mvprintw(6, 0, "(Current trace level is %s)", tracetrace(_nc_tracing));
  3407.  
  3408.     refresh();
  3409.  
  3410.     for (n = 0; t_tbl[n].name != 0; n++)
  3411.     *ip++ = new_item(t_tbl[n].name, "");
  3412.     *ip = (ITEM *) 0;
  3413.  
  3414.     m = new_menu(items);
  3415.  
  3416.     set_menu_format(m, 0, 2);
  3417.     scale_menu(m, &mrows, &mcols);
  3418.  
  3419.     menu_opts_off(m, O_ONEVALUE);
  3420.     menuwin = newwin(mrows + 2, mcols + 2, MENU_Y, MENU_X);
  3421.     set_menu_win(m, menuwin);
  3422.     keypad(menuwin, TRUE);
  3423.     box(menuwin, 0, 0);
  3424.  
  3425.     set_menu_sub(m, derwin(menuwin, mrows, mcols, 1, 1));
  3426.  
  3427.     post_menu(m);
  3428.  
  3429.     for (ip = menu_items(m); *ip; ip++) {
  3430.     int mask = t_tbl[item_index(*ip)].mask;
  3431.     if (mask == 0)
  3432.         set_item_value(*ip, _nc_tracing == 0);
  3433.     else if ((mask & _nc_tracing) == mask)
  3434.         set_item_value(*ip, TRUE);
  3435.     }
  3436.  
  3437.     while (run_trace_menu(m))
  3438.     continue;
  3439.  
  3440.     newtrace = 0;
  3441.     for (ip = menu_items(m); *ip; ip++)
  3442.     if (item_value(*ip))
  3443.         newtrace |= t_tbl[item_index(*ip)].mask;
  3444.     trace(newtrace);
  3445.     _tracef("trace level interactively set to %s", tracetrace(_nc_tracing));
  3446.  
  3447.     (void) mvprintw(LINES - 2, 0,
  3448.             "Trace level is %s\n", tracetrace(_nc_tracing));
  3449.     (void) addstr("Press any key to continue...");
  3450.     wGetchar(stdscr);
  3451.  
  3452.     unpost_menu(m);
  3453.     delwin(menuwin);
  3454.  
  3455.     free_menu(m);
  3456.     for (ip = items; *ip; ip++)
  3457.     free_item(*ip);
  3458. }
  3459. #endif /* TRACE */
  3460. #endif /* USE_LIBMENU */
  3461.  
  3462. /****************************************************************************
  3463.  *
  3464.  * Forms test
  3465.  *
  3466.  ****************************************************************************/
  3467. #if USE_LIBFORM
  3468. static FIELD *
  3469. make_label(int frow, int fcol, NCURSES_CONST char *label)
  3470. {
  3471.     FIELD *f = new_field(1, strlen(label), frow, fcol, 0, 0);
  3472.  
  3473.     if (f) {
  3474.     set_field_buffer(f, 0, label);
  3475.     set_field_opts(f, field_opts(f) & ~O_ACTIVE);
  3476.     }
  3477.     return (f);
  3478. }
  3479.  
  3480. static FIELD *
  3481. make_field(int frow, int fcol, int rows, int cols, bool secure)
  3482. {
  3483.     FIELD *f = new_field(rows, cols, frow, fcol, 0, secure ? 1 : 0);
  3484.  
  3485.     if (f) {
  3486.     set_field_back(f, A_UNDERLINE);
  3487.     set_field_userptr(f, (void *) 0);
  3488.     }
  3489.     return (f);
  3490. }
  3491.  
  3492. static void
  3493. display_form(FORM * f)
  3494. {
  3495.     WINDOW *w;
  3496.     int rows, cols;
  3497.  
  3498.     scale_form(f, &rows, &cols);
  3499.  
  3500.     if ((w = newwin(rows + 2, cols + 4, 0, 0)) != (WINDOW *) 0) {
  3501.     set_form_win(f, w);
  3502.     set_form_sub(f, derwin(w, rows, cols, 1, 2));
  3503.     box(w, 0, 0);
  3504.     keypad(w, TRUE);
  3505.     }
  3506.  
  3507.     if (post_form(f) != E_OK)
  3508.     wrefresh(w);
  3509. }
  3510.  
  3511. static void
  3512. erase_form(FORM * f)
  3513. {
  3514.     WINDOW *w = form_win(f);
  3515.     WINDOW *s = form_sub(f);
  3516.  
  3517.     unpost_form(f);
  3518.     werase(w);
  3519.     wrefresh(w);
  3520.     delwin(s);
  3521.     delwin(w);
  3522. }
  3523.  
  3524. static int
  3525. edit_secure(FIELD * me, int c)
  3526. {
  3527.     int rows, cols, frow, fcol, nrow, nbuf;
  3528.  
  3529.     if (field_info(me, &rows, &cols, &frow, &fcol, &nrow, &nbuf) == E_OK
  3530.     && nbuf > 0) {
  3531.     char temp[80];
  3532.     long len;
  3533.  
  3534.     strcpy(temp, field_buffer(me, 1));
  3535.     len = (long) (char *) field_userptr(me);
  3536.     if (c <= KEY_MAX) {
  3537.         if (isgraph(c)) {
  3538.         temp[len++] = c;
  3539.         temp[len] = 0;
  3540.         set_field_buffer(me, 1, temp);
  3541.         c = '*';
  3542.         } else {
  3543.         c = 0;
  3544.         }
  3545.     } else {
  3546.         switch (c) {
  3547.         case REQ_BEG_FIELD:
  3548.         case REQ_CLR_EOF:
  3549.         case REQ_CLR_EOL:
  3550.         case REQ_DEL_LINE:
  3551.         case REQ_DEL_WORD:
  3552.         case REQ_DOWN_CHAR:
  3553.         case REQ_END_FIELD:
  3554.         case REQ_INS_CHAR:
  3555.         case REQ_INS_LINE:
  3556.         case REQ_LEFT_CHAR:
  3557.         case REQ_NEW_LINE:
  3558.         case REQ_NEXT_WORD:
  3559.         case REQ_PREV_WORD:
  3560.         case REQ_RIGHT_CHAR:
  3561.         case REQ_UP_CHAR:
  3562.         c = 0;        /* we don't want to do inline editing */
  3563.         break;
  3564.         case REQ_CLR_FIELD:
  3565.         if (len) {
  3566.             temp[0] = 0;
  3567.             set_field_buffer(me, 1, temp);
  3568.         }
  3569.         break;
  3570.         case REQ_DEL_CHAR:
  3571.         case REQ_DEL_PREV:
  3572.         if (len) {
  3573.             temp[--len] = 0;
  3574.             set_field_buffer(me, 1, temp);
  3575.         }
  3576.         break;
  3577.         }
  3578.     }
  3579.     set_field_userptr(me, (void *) len);
  3580.     }
  3581.     return c;
  3582. }
  3583.  
  3584. static int
  3585. form_virtualize(FORM * f, WINDOW *w)
  3586. {
  3587.     static const struct {
  3588.     int code;
  3589.     int result;
  3590.     } lookup[] = {
  3591.     {
  3592.         CTRL('A'), REQ_NEXT_CHOICE
  3593.     },
  3594.     {
  3595.         CTRL('B'), REQ_PREV_WORD
  3596.     },
  3597.     {
  3598.         CTRL('C'), REQ_CLR_EOL
  3599.     },
  3600.     {
  3601.         CTRL('D'), REQ_DOWN_FIELD
  3602.     },
  3603.     {
  3604.         CTRL('E'), REQ_END_FIELD
  3605.     },
  3606.     {
  3607.         CTRL('F'), REQ_NEXT_PAGE
  3608.     },
  3609.     {
  3610.         CTRL('G'), REQ_DEL_WORD
  3611.     },
  3612.     {
  3613.         CTRL('H'), REQ_DEL_PREV
  3614.     },
  3615.     {
  3616.         CTRL('I'), REQ_INS_CHAR
  3617.     },
  3618.     {
  3619.         CTRL('K'), REQ_CLR_EOF
  3620.     },
  3621.     {
  3622.         CTRL('L'), REQ_LEFT_FIELD
  3623.     },
  3624.     {
  3625.         CTRL('M'), REQ_NEW_LINE
  3626.     },
  3627.     {
  3628.         CTRL('N'), REQ_NEXT_FIELD
  3629.     },
  3630.     {
  3631.         CTRL('O'), REQ_INS_LINE
  3632.     },
  3633.     {
  3634.         CTRL('P'), REQ_PREV_FIELD
  3635.     },
  3636.     {
  3637.         CTRL('R'), REQ_RIGHT_FIELD
  3638.     },
  3639.     {
  3640.         CTRL('S'), REQ_BEG_FIELD
  3641.     },
  3642.     {
  3643.         CTRL('U'), REQ_UP_FIELD
  3644.     },
  3645.     {
  3646.         CTRL('V'), REQ_DEL_CHAR
  3647.     },
  3648.     {
  3649.         CTRL('W'), REQ_NEXT_WORD
  3650.     },
  3651.     {
  3652.         CTRL('X'), REQ_CLR_FIELD
  3653.     },
  3654.     {
  3655.         CTRL('Y'), REQ_DEL_LINE
  3656.     },
  3657.     {
  3658.         CTRL('Z'), REQ_PREV_CHOICE
  3659.     },
  3660.     {
  3661.         ESCAPE, MAX_FORM_COMMAND + 1
  3662.     },
  3663.     {
  3664.         KEY_BACKSPACE, REQ_DEL_PREV
  3665.     },
  3666.     {
  3667.         KEY_DOWN, REQ_DOWN_CHAR
  3668.     },
  3669.     {
  3670.         KEY_END, REQ_LAST_FIELD
  3671.     },
  3672.     {
  3673.         KEY_HOME, REQ_FIRST_FIELD
  3674.     },
  3675.     {
  3676.         KEY_LEFT, REQ_LEFT_CHAR
  3677.     },
  3678.     {
  3679.         KEY_LL, REQ_LAST_FIELD
  3680.     },
  3681.     {
  3682.         KEY_NEXT, REQ_NEXT_FIELD
  3683.     },
  3684.     {
  3685.         KEY_NPAGE, REQ_NEXT_PAGE
  3686.     },
  3687.     {
  3688.         KEY_PPAGE, REQ_PREV_PAGE
  3689.     },
  3690.     {
  3691.         KEY_PREVIOUS, REQ_PREV_FIELD
  3692.     },
  3693.     {
  3694.         KEY_RIGHT, REQ_RIGHT_CHAR
  3695.     },
  3696.     {
  3697.         KEY_UP, REQ_UP_CHAR
  3698.     },
  3699.     {
  3700.         QUIT, MAX_FORM_COMMAND + 1
  3701.     }
  3702.     };
  3703.  
  3704.     static int mode = REQ_INS_MODE;
  3705.     int c = wGetchar(w);
  3706.     unsigned n;
  3707.     FIELD *me = current_field(f);
  3708.  
  3709.     if (c == CTRL(']')) {
  3710.     if (mode == REQ_INS_MODE)
  3711.         mode = REQ_OVL_MODE;
  3712.     else
  3713.         mode = REQ_INS_MODE;
  3714.     c = mode;
  3715.     } else {
  3716.     for (n = 0; n < SIZEOF(lookup); n++) {
  3717.         if (lookup[n].code == c) {
  3718.         c = lookup[n].result;
  3719.         break;
  3720.         }
  3721.     }
  3722.     }
  3723.  
  3724.     /*
  3725.      * Force the field that the user is typing into to be in reverse video,
  3726.      * while the other fields are shown underlined.
  3727.      */
  3728.     if (c <= KEY_MAX) {
  3729.     c = edit_secure(me, c);
  3730.     set_field_back(me, A_REVERSE);
  3731.     } else if (c <= MAX_FORM_COMMAND) {
  3732.     c = edit_secure(me, c);
  3733.     set_field_back(me, A_UNDERLINE);
  3734.     }
  3735.     return c;
  3736. }
  3737.  
  3738. static int
  3739. my_form_driver(FORM * form, int c)
  3740. {
  3741.     if (c == (MAX_FORM_COMMAND + 1)
  3742.     && form_driver(form, REQ_VALIDATION) == E_OK)
  3743.     return (TRUE);
  3744.     else {
  3745.     beep();
  3746.     return (FALSE);
  3747.     }
  3748. }
  3749.  
  3750. static void
  3751. demo_forms(void)
  3752. {
  3753.     WINDOW *w;
  3754.     FORM *form;
  3755.     FIELD *f[12], *secure;
  3756.     int finished = 0, c;
  3757.     unsigned n = 0;
  3758.  
  3759.     move(18, 0);
  3760.     addstr("Defined form-traversal keys:   ^Q/ESC- exit form\n");
  3761.     addstr("^N   -- go to next field       ^P  -- go to previous field\n");
  3762.     addstr("Home -- go to first field      End -- go to last field\n");
  3763.     addstr("^L   -- go to field to left    ^R  -- go to field to right\n");
  3764.     addstr("^U   -- move upward to field   ^D  -- move downward to field\n");
  3765.     addstr("^W   -- go to next word        ^B  -- go to previous word\n");
  3766.     addstr("^S   -- go to start of field   ^E  -- go to end of field\n");
  3767.     addstr("^H   -- delete previous char   ^Y  -- delete line\n");
  3768.     addstr("^G   -- delete current word    ^C  -- clear to end of line\n");
  3769.     addstr("^K   -- clear to end of field  ^X  -- clear field\n");
  3770.     addstr("Arrow keys move within a field as you would expect.");
  3771.  
  3772.     mvaddstr(4, 57, "Forms Entry Test");
  3773.  
  3774.     refresh();
  3775.  
  3776.     /* describe the form */
  3777.     f[n++] = make_label(0, 15, "Sample Form");
  3778.     f[n++] = make_label(2, 0, "Last Name");
  3779.     f[n++] = make_field(3, 0, 1, 18, FALSE);
  3780.     f[n++] = make_label(2, 20, "First Name");
  3781.     f[n++] = make_field(3, 20, 1, 12, FALSE);
  3782.     f[n++] = make_label(2, 34, "Middle Name");
  3783.     f[n++] = make_field(3, 34, 1, 12, FALSE);
  3784.     f[n++] = make_label(5, 0, "Comments");
  3785.     f[n++] = make_field(6, 0, 4, 46, FALSE);
  3786.     f[n++] = make_label(5, 20, "Password:");
  3787.     secure =
  3788.     f[n++] = make_field(5, 30, 1, 9, TRUE);
  3789.     f[n++] = (FIELD *) 0;
  3790.  
  3791.     form = new_form(f);
  3792.  
  3793.     display_form(form);
  3794.  
  3795.     w = form_win(form);
  3796.     raw();
  3797.     nonl();            /* lets us read ^M's */
  3798.     while (!finished) {
  3799.     switch (form_driver(form, c = form_virtualize(form, w))) {
  3800.     case E_OK:
  3801.         mvaddstr(5, 57, field_buffer(secure, 1));
  3802.         clrtoeol();
  3803.         refresh();
  3804.         break;
  3805.     case E_UNKNOWN_COMMAND:
  3806.         finished = my_form_driver(form, c);
  3807.         break;
  3808.     default:
  3809.         beep();
  3810.         break;
  3811.     }
  3812.     }
  3813.  
  3814.     erase_form(form);
  3815.  
  3816.     free_form(form);
  3817.     for (c = 0; f[c] != 0; c++)
  3818.     free_field(f[c]);
  3819.     noraw();
  3820.     nl();
  3821. }
  3822. #endif /* USE_LIBFORM */
  3823.  
  3824. /****************************************************************************
  3825.  *
  3826.  * Overlap test
  3827.  *
  3828.  ****************************************************************************/
  3829.  
  3830. static void
  3831. fillwin(WINDOW *win, char ch)
  3832. {
  3833.     int y, x;
  3834.     int y1, x1;
  3835.  
  3836.     getmaxyx(win, y1, x1);
  3837.     for (y = 0; y < y1; y++) {
  3838.     wmove(win, y, 0);
  3839.     for (x = 0; x < x1; x++)
  3840.         waddch(win, ch);
  3841.     }
  3842. }
  3843.  
  3844. static void
  3845. crosswin(WINDOW *win, char ch)
  3846. {
  3847.     int y, x;
  3848.     int y1, x1;
  3849.  
  3850.     getmaxyx(win, y1, x1);
  3851.     for (y = 0; y < y1; y++) {
  3852.     for (x = 0; x < x1; x++)
  3853.         if (((x > (x1 - 1) / 3) && (x <= (2 * (x1 - 1)) / 3))
  3854.         || (((y > (y1 - 1) / 3) && (y <= (2 * (y1 - 1)) / 3)))) {
  3855.         wmove(win, y, x);
  3856.         waddch(win, ch);
  3857.         }
  3858.     }
  3859. }
  3860.  
  3861. static void
  3862. overlap_test(void)
  3863. /* test effects of overlapping windows */
  3864. {
  3865.     int ch;
  3866.  
  3867.     WINDOW *win1 = newwin(9, 20, 3, 3);
  3868.     WINDOW *win2 = newwin(9, 20, 9, 16);
  3869.  
  3870.     raw();
  3871.     refresh();
  3872.     move(0, 0);
  3873.     printw("This test shows the behavior of wnoutrefresh() with respect to\n");
  3874.     printw("the shared region of two overlapping windows A and B.  The cross\n");
  3875.     printw("pattern in each window does not overlap the other.\n");
  3876.  
  3877.     move(18, 0);
  3878.     printw("a = refresh A, then B, then doupdate. b = refresh B, then A, then doupdaute\n");
  3879.     printw("c = fill window A with letter A.      d = fill window B with letter B.\n");
  3880.     printw("e = cross pattern in window A.        f = cross pattern in window B.\n");
  3881.     printw("g = clear window A.                   h = clear window B.\n");
  3882.     printw("i = overwrite A onto B.               j = overwrite B onto A.\n");
  3883.     printw("^Q/ESC = terminate test.");
  3884.  
  3885.     while ((ch = Getchar()) != QUIT && ch != ESCAPE)
  3886.     switch (ch) {
  3887.     case 'a':        /* refresh window A first, then B */
  3888.         wnoutrefresh(win1);
  3889.         wnoutrefresh(win2);
  3890.         doupdate();
  3891.         break;
  3892.  
  3893.     case 'b':        /* refresh window B first, then A */
  3894.         wnoutrefresh(win2);
  3895.         wnoutrefresh(win1);
  3896.         doupdate();
  3897.         break;
  3898.  
  3899.     case 'c':        /* fill window A so it's visible */
  3900.         fillwin(win1, 'A');
  3901.         break;
  3902.  
  3903.     case 'd':        /* fill window B so it's visible */
  3904.         fillwin(win2, 'B');
  3905.         break;
  3906.  
  3907.     case 'e':        /* cross test pattern in window A */
  3908.         crosswin(win1, 'A');
  3909.         break;
  3910.  
  3911.     case 'f':        /* cross test pattern in window A */
  3912.         crosswin(win2, 'B');
  3913.         break;
  3914.  
  3915.     case 'g':        /* clear window A */
  3916.         wclear(win1);
  3917.         wmove(win1, 0, 0);
  3918.         break;
  3919.  
  3920.     case 'h':        /* clear window B */
  3921.         wclear(win2);
  3922.         wmove(win2, 0, 0);
  3923.         break;
  3924.  
  3925.     case 'i':        /* overwrite A onto B */
  3926.         overwrite(win1, win2);
  3927.         break;
  3928.  
  3929.     case 'j':        /* overwrite B onto A */
  3930.         overwrite(win2, win1);
  3931.         break;
  3932.     }
  3933.  
  3934.     delwin(win2);
  3935.     delwin(win1);
  3936.     erase();
  3937.     endwin();
  3938. }
  3939.  
  3940. /****************************************************************************
  3941.  *
  3942.  * Main sequence
  3943.  *
  3944.  ****************************************************************************/
  3945.  
  3946. static bool
  3947. do_single_test(const char c)
  3948. /* perform a single specified test */
  3949. {
  3950.     switch (c) {
  3951.     case 'a':
  3952.     getch_test();
  3953.     break;
  3954.  
  3955. #if USE_WIDEC_SUPPORT
  3956.     case 'A':
  3957.     get_wch_test();
  3958.     break;
  3959. #endif
  3960.  
  3961.     case 'b':
  3962.     attr_test();
  3963.     break;
  3964.  
  3965.     case 'c':
  3966.     if (!has_colors())
  3967.         Cannot("does not support color.");
  3968.     else
  3969.         color_test();
  3970.     break;
  3971.  
  3972.     case 'd':
  3973.     if (!has_colors())
  3974.         Cannot("does not support color.");
  3975.     else if (!can_change_color())
  3976.         Cannot("has hardwired color values.");
  3977.     else
  3978.         color_edit();
  3979.     break;
  3980.  
  3981.     case 'e':
  3982.     slk_test();
  3983.     break;
  3984.  
  3985.     case 'f':
  3986.     acs_display();
  3987.     break;
  3988.  
  3989. #if USE_WIDEC_SUPPORT
  3990.     case 'F':
  3991.     wide_acs_display();
  3992.     break;
  3993. #endif
  3994.  
  3995. #if USE_LIBPANEL
  3996.     case 'o':
  3997.     demo_panels();
  3998.     break;
  3999. #endif
  4000.  
  4001.     case 'g':
  4002.     acs_and_scroll();
  4003.     break;
  4004.  
  4005.     case 'i':
  4006.     flushinp_test(stdscr);
  4007.     break;
  4008.  
  4009.     case 'k':
  4010.     test_sgr_attributes();
  4011.     break;
  4012.  
  4013. #if USE_LIBMENU
  4014.     case 'm':
  4015.     menu_test();
  4016.     break;
  4017. #endif
  4018.  
  4019. #if USE_LIBPANEL
  4020.     case 'p':
  4021.     demo_pad();
  4022.     break;
  4023. #endif
  4024.  
  4025. #if USE_LIBFORM
  4026.     case 'r':
  4027.     demo_forms();
  4028.     break;
  4029. #endif
  4030.  
  4031.     case 's':
  4032.     overlap_test();
  4033.     break;
  4034.  
  4035. #if USE_LIBMENU && defined(TRACE)
  4036.     case 't':
  4037.     trace_set();
  4038.     break;
  4039. #endif
  4040.  
  4041.     case '?':
  4042.     break;
  4043.  
  4044.     default:
  4045.     return FALSE;
  4046.     }
  4047.  
  4048.     return TRUE;
  4049. }
  4050.  
  4051. static void
  4052. usage(void)
  4053. {
  4054.     static const char *const tbl[] =
  4055.     {
  4056.     "Usage: ncurses [options]"
  4057.     ,""
  4058.     ,"Options:"
  4059. #ifdef NCURSES_VERSION
  4060.     ,"  -a f,b   set default-colors (assumed white-on-black)"
  4061.     ,"  -d       use default-colors if terminal supports them"
  4062. #endif
  4063.     ,"  -e fmt   specify format for soft-keys test (e)"
  4064.     ,"  -f       rip-off footer line (can repeat)"
  4065.     ,"  -h       rip-off header line (can repeat)"
  4066.     ,"  -s msec  specify nominal time for panel-demo (default: 1, to hold)"
  4067. #ifdef TRACE
  4068.     ,"  -t mask  specify default trace-level (may toggle with ^T)"
  4069. #endif
  4070.     };
  4071.     size_t n;
  4072.     for (n = 0; n < SIZEOF(tbl); n++)
  4073.     fprintf(stderr, "%s\n", tbl[n]);
  4074.     ExitProgram(EXIT_FAILURE);
  4075. }
  4076.  
  4077. static void
  4078. set_terminal_modes(void)
  4079. {
  4080.     noraw();
  4081.     cbreak();
  4082.     noecho();
  4083.     scrollok(stdscr, TRUE);
  4084.     idlok(stdscr, TRUE);
  4085.     keypad(stdscr, TRUE);
  4086. }
  4087.  
  4088. #ifdef SIGUSR1
  4089. static RETSIGTYPE
  4090. announce_sig(int sig)
  4091. {
  4092.     (void) fprintf(stderr, "Handled signal %d\r\n", sig);
  4093. }
  4094. #endif
  4095.  
  4096. static int
  4097. rip_footer(WINDOW *win, int cols)
  4098. {
  4099.     wbkgd(win, A_REVERSE);
  4100.     werase(win);
  4101.     wmove(win, 0, 0);
  4102.     wprintw(win, "footer: %d columns", cols);
  4103.     wnoutrefresh(win);
  4104.     return OK;
  4105. }
  4106.  
  4107. static int
  4108. rip_header(WINDOW *win, int cols)
  4109. {
  4110.     wbkgd(win, A_REVERSE);
  4111.     werase(win);
  4112.     wmove(win, 0, 0);
  4113.     wprintw(win, "header: %d columns", cols);
  4114.     wnoutrefresh(win);
  4115.     return OK;
  4116. }
  4117.  
  4118. /*+-------------------------------------------------------------------------
  4119.     main(argc,argv)
  4120. --------------------------------------------------------------------------*/
  4121.  
  4122. int
  4123. main(int argc, char *argv[])
  4124. {
  4125.     int command, c;
  4126.     int my_e_param = 1;
  4127. #ifdef NCURSES_VERSION
  4128.     int default_fg = COLOR_WHITE;
  4129.     int default_bg = COLOR_BLACK;
  4130.     bool assumed_colors = FALSE;
  4131.     bool default_colors = FALSE;
  4132. #endif
  4133.  
  4134.     setlocale(LC_ALL, "");
  4135.  
  4136.     while ((c = getopt(argc, argv, "a:de:fhs:t:")) != EOF) {
  4137.     switch (c) {
  4138. #ifdef NCURSES_VERSION
  4139.     case 'a':
  4140.         assumed_colors = TRUE;
  4141.         sscanf(optarg, "%d,%d", &default_fg, &default_bg);
  4142.         break;
  4143.     case 'd':
  4144.         default_colors = TRUE;
  4145.         break;
  4146. #endif
  4147.     case 'e':
  4148.         my_e_param = atoi(optarg);
  4149. #ifdef NCURSES_VERSION
  4150.         if (my_e_param > 3)    /* allow extended layouts */
  4151.         usage();
  4152. #else
  4153.         if (my_e_param > 1)
  4154.         usage();
  4155. #endif
  4156.         break;
  4157.     case 'f':
  4158.         ripoffline(-1, rip_footer);
  4159.         break;
  4160.     case 'h':
  4161.         ripoffline(1, rip_header);
  4162.         break;
  4163. #if USE_LIBPANEL
  4164.     case 's':
  4165.         nap_msec = atol(optarg);
  4166.         break;
  4167. #endif
  4168. #ifdef TRACE
  4169.     case 't':
  4170.         save_trace = atoi(optarg);
  4171.         break;
  4172. #endif
  4173.     default:
  4174.         usage();
  4175.     }
  4176.     }
  4177.  
  4178.     /*
  4179.      * If there's no menus (unlikely for ncurses!), then we'll have to set
  4180.      * tracing on initially, just in case the user wants to test something that
  4181.      * doesn't involve wGetchar.
  4182.      */
  4183. #ifdef TRACE
  4184.     /* enable debugging */
  4185. #if !USE_LIBMENU
  4186.     trace(save_trace);
  4187. #else
  4188.     if (!isatty(fileno(stdin)))
  4189.     trace(save_trace);
  4190. #endif /* USE_LIBMENU */
  4191. #endif /* TRACE */
  4192.  
  4193.     /* tell it we're going to play with soft keys */
  4194.     slk_init(my_e_param);
  4195.  
  4196. #ifdef SIGUSR1
  4197.     /* set up null signal catcher so we can see what interrupts to getch do */
  4198.     signal(SIGUSR1, announce_sig);
  4199. #endif
  4200.  
  4201.     /* we must initialize the curses data structure only once */
  4202.     initscr();
  4203.     bkgdset(BLANK);
  4204.  
  4205.     /* tests, in general, will want these modes */
  4206.     if (has_colors()) {
  4207.     start_color();
  4208. #ifdef NCURSES_VERSION_PATCH
  4209.     max_colors = COLORS > 16 ? 16 : COLORS;
  4210. #if HAVE_USE_DEFAULT_COLORS
  4211.     if (default_colors)
  4212.         use_default_colors();
  4213. #if NCURSES_VERSION_PATCH >= 20000708
  4214.     else if (assumed_colors)
  4215.         assume_default_colors(default_fg, default_bg);
  4216. #endif
  4217. #endif
  4218. #else /* normal SVr4 curses */
  4219.     max_colors = COLORS > 8 ? 8 : COLORS;
  4220. #endif
  4221.     max_pairs = (max_colors * max_colors);
  4222.     if (max_pairs < COLOR_PAIRS)
  4223.         max_pairs = COLOR_PAIRS;
  4224.     }
  4225.     set_terminal_modes();
  4226.     def_prog_mode();
  4227.  
  4228.     /*
  4229.      * Return to terminal mode, so we're guaranteed of being able to
  4230.      * select terminal commands even if the capabilities are wrong.
  4231.      */
  4232.     endwin();
  4233.  
  4234. #if HAVE_CURSES_VERSION
  4235.     (void) printf("Welcome to %s.  Press ? for help.\n", curses_version());
  4236. #elif defined(NCURSES_VERSION_MAJOR) && defined(NCURSES_VERSION_MINOR) && defined(NCURSES_VERSION_PATCH)
  4237.     (void) printf("Welcome to ncurses %d.%d.%d.  Press ? for help.\n",
  4238.           NCURSES_VERSION_MAJOR,
  4239.           NCURSES_VERSION_MINOR,
  4240.           NCURSES_VERSION_PATCH);
  4241. #else
  4242.     (void) puts("Welcome to ncurses.  Press ? for help.");
  4243. #endif
  4244.  
  4245.     do {
  4246.     (void) puts("This is the ncurses main menu");
  4247.     (void) puts("a = keyboard and mouse input test");
  4248. #if USE_WIDEC_SUPPORT
  4249.     (void) puts("A = wide-character keyboard and mouse input test");
  4250. #endif
  4251.     (void) puts("b = character attribute test");
  4252.     (void) puts("c = color test pattern");
  4253.     (void) puts("d = edit RGB color values");
  4254.     (void) puts("e = exercise soft keys");
  4255.     (void) puts("f = display ACS characters");
  4256. #if USE_WIDEC_SUPPORT
  4257.     (void) puts("F = display Wide-ACS characters");
  4258. #endif
  4259.     (void) puts("g = display windows and scrolling");
  4260.     (void) puts("i = test of flushinp()");
  4261.     (void) puts("k = display character attributes");
  4262. #if USE_LIBMENU
  4263.     (void) puts("m = menu code test");
  4264. #endif
  4265. #if USE_LIBPANEL
  4266.     (void) puts("o = exercise panels library");
  4267.     (void) puts("p = exercise pad features");
  4268.     (void) puts("q = quit");
  4269. #endif
  4270. #if USE_LIBFORM
  4271.     (void) puts("r = exercise forms code");
  4272. #endif
  4273.     (void) puts("s = overlapping-refresh test");
  4274. #if USE_LIBMENU && defined(TRACE)
  4275.     (void) puts("t = set trace level");
  4276. #endif
  4277.     (void) puts("? = repeat this command summary");
  4278.  
  4279.     (void) fputs("> ", stdout);
  4280.     (void) fflush(stdout);    /* necessary under SVr4 curses */
  4281.  
  4282.     /*
  4283.      * This used to be an 'fgets()' call.  However (on Linux, at least)
  4284.      * mixing stream I/O and 'read()' (used in the library) causes the
  4285.      * input stream to be flushed when switching between the two.
  4286.      */
  4287.     command = 0;
  4288.     for (;;) {
  4289.         char ch;
  4290.         if (read(fileno(stdin), &ch, 1) <= 0) {
  4291.         if (command == 0)
  4292.             command = 'q';
  4293.         break;
  4294.         } else if (command == 0 && !isspace(UChar(ch))) {
  4295.         command = ch;
  4296.         } else if (ch == '\n' || ch == '\r') {
  4297.         if (command != 0)
  4298.             break;
  4299.         (void) fputs("> ", stdout);
  4300.         (void) fflush(stdout);
  4301.         }
  4302.     }
  4303.  
  4304.     if (do_single_test(command)) {
  4305.         /*
  4306.          * This may be overkill; it's intended to reset everything back
  4307.          * to the initial terminal modes so that tests don't get in
  4308.          * each other's way.
  4309.          */
  4310.         flushinp();
  4311.         set_terminal_modes();
  4312.         reset_prog_mode();
  4313.         clear();
  4314.         refresh();
  4315.         endwin();
  4316.         if (command == '?') {
  4317.         (void) puts("This is the ncurses capability tester.");
  4318.         (void)
  4319.             puts("You may select a test from the main menu by typing the");
  4320.         (void)
  4321.             puts("key letter of the choice (the letter to left of the =)");
  4322.         (void)
  4323.             puts("at the > prompt.  The commands `x' or `q' will exit.");
  4324.         }
  4325.         continue;
  4326.     }
  4327.     } while
  4328.     (command != 'q');
  4329.  
  4330.     ExitProgram(EXIT_SUCCESS);
  4331. }
  4332.  
  4333. /* ncurses.c ends here */
  4334.